6367 Provide a text-installer for opensolaris
authorKeith Mitchell <keith.mitchell@sun.com>
Tue, 16 Mar 2010 14:07:17 -0700
changeset 773 cc0753f47d02
parent 772 402b6c262e9d
child 774 e127cdda9eb0
6367 Provide a text-installer for opensolaris 1223 installer should preserve existing Solaris slice(s)
usr/src/Makefile.master
usr/src/README
usr/src/Targetdirs
usr/src/cmd/Makefile
usr/src/cmd/Makefile.cmd
usr/src/cmd/Makefile.targ
usr/src/cmd/distro_const/Makefile
usr/src/cmd/distro_const/auto_install/Makefile
usr/src/cmd/distro_const/auto_install/ai_plat_setup.py
usr/src/cmd/distro_const/auto_install/ai_post_boot_archive_pkg_image_mod
usr/src/cmd/distro_const/auto_install/ai_sparc_image.xml
usr/src/cmd/distro_const/auto_install/ai_x86_image.xml
usr/src/cmd/distro_const/slim_cd/Makefile
usr/src/cmd/distro_const/slim_cd/all_lang_slim_cd_x86.xml
usr/src/cmd/distro_const/slim_cd/slim_cd_x86.xml
usr/src/cmd/distro_const/slim_cd/slimcd_gen_cd_content
usr/src/cmd/distro_const/text_install/Makefile
usr/src/cmd/distro_const/text_install/text_live.xml
usr/src/cmd/distro_const/text_install/text_mode_sparc.xml
usr/src/cmd/distro_const/text_install/text_mode_x86.xml
usr/src/cmd/distro_const/text_install/tm_pre_boot_archive_pkg_image_mod
usr/src/cmd/distro_const/utils/Makefile
usr/src/cmd/distro_const/utils/gen_cd_content
usr/src/cmd/distro_const/utils/grub_setup.py
usr/src/cmd/distro_const/utils/plat_setup.py
usr/src/cmd/distro_const/utils/post_boot_archive_pkg_image_mod_custom
usr/src/cmd/slim-install/config/set_lang
usr/src/cmd/slim-install/finish/install-finish
usr/src/cmd/slim-install/svc/media-fs-root
usr/src/cmd/text-install/Makefile
usr/src/cmd/text-install/helpfiles/Makefile
usr/src/cmd/text-install/helpfiles/date_time.txt
usr/src/cmd/text-install/helpfiles/disks.txt
usr/src/cmd/text-install/helpfiles/network.txt
usr/src/cmd/text-install/helpfiles/network_manual.txt
usr/src/cmd/text-install/helpfiles/sparc_solaris_slices.txt
usr/src/cmd/text-install/helpfiles/sparc_solaris_slices_select.txt
usr/src/cmd/text-install/helpfiles/summary.txt
usr/src/cmd/text-install/helpfiles/timezone.txt
usr/src/cmd/text-install/helpfiles/users.txt
usr/src/cmd/text-install/helpfiles/welcome.txt
usr/src/cmd/text-install/helpfiles/x86_fdisk_partitions.txt
usr/src/cmd/text-install/helpfiles/x86_fdisk_partitions_select.txt
usr/src/cmd/text-install/helpfiles/x86_fdisk_slices.txt
usr/src/cmd/text-install/helpfiles/x86_fdisk_slices_select.txt
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/ip_address.py
usr/src/cmd/text-install/osol_install/profile/network_info.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/profile/system_info.py
usr/src/cmd/text-install/osol_install/profile/user_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/action.py
usr/src/cmd/text-install/osol_install/text_install/base_screen.py
usr/src/cmd/text-install/osol_install/text_install/color_theme.py
usr/src/cmd/text-install/osol_install/text_install/date_time.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/edit_field.py
usr/src/cmd/text-install/osol_install/text_install/error_window.py
usr/src/cmd/text-install/osol_install/text_install/fdisk_partitions.py
usr/src/cmd/text-install/osol_install/text_install/help_screen.py
usr/src/cmd/text-install/osol_install/text_install/inner_window.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/list_item.py
usr/src/cmd/text-install/osol_install/text_install/log_viewer.py
usr/src/cmd/text-install/osol_install/text_install/main_window.py
usr/src/cmd/text-install/osol_install/text_install/network_nic_configure.py
usr/src/cmd/text-install/osol_install/text_install/network_nic_select.py
usr/src/cmd/text-install/osol_install/text_install/network_type.py
usr/src/cmd/text-install/osol_install/text_install/partition_edit_screen.py
usr/src/cmd/text-install/osol_install/text_install/screen_list.py
usr/src/cmd/text-install/osol_install/text_install/scroll_window.py
usr/src/cmd/text-install/osol_install/text_install/summary.py
usr/src/cmd/text-install/osol_install/text_install/text_install.py
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/timezone.py
usr/src/cmd/text-install/osol_install/text_install/users.py
usr/src/cmd/text-install/osol_install/text_install/welcome.py
usr/src/cmd/text-install/osol_install/text_install/window_area.py
usr/src/cmd/text-install/svc/Makefile
usr/src/cmd/text-install/svc/text-mode-menu.ksh
usr/src/cmd/text-install/svc/text-mode-menu.xml
usr/src/lib/Makefile
usr/src/lib/libict/Makefile
usr/src/lib/libict_pymod/ict.py
usr/src/lib/libtarget_pymod/Makefile
usr/src/lib/libtarget_pymod/discover.c
usr/src/lib/libtarget_pymod/disk.c
usr/src/lib/libtarget_pymod/disk.h
usr/src/lib/libtarget_pymod/geometry.c
usr/src/lib/libtarget_pymod/geometry.h
usr/src/lib/libtarget_pymod/instantiate.c
usr/src/lib/libtarget_pymod/mapfile-vers
usr/src/lib/libtarget_pymod/partition.c
usr/src/lib/libtarget_pymod/partition.h
usr/src/lib/libtarget_pymod/slice.c
usr/src/lib/libtarget_pymod/slice.h
usr/src/lib/libtarget_pymod/tgt.c
usr/src/lib/libtarget_pymod/tgt.h
usr/src/lib/libtarget_pymod/tgt_utils.py
usr/src/lib/libtarget_pymod/zpool.c
usr/src/lib/libtarget_pymod/zpool.h
usr/src/lib/libtd/Makefile
usr/src/lib/libtd/td_api.h
usr/src/lib/libtd/td_dd.c
usr/src/lib/libtd/td_dd.h
usr/src/lib/libtd/test_td.c
usr/src/lib/libti/Makefile
usr/src/lib/libti/ti_api.h
usr/src/lib/libti/ti_dm.c
usr/src/lib/libtransfer/transfer_mod.py
usr/src/lib/libzoneinfo_pymod/Makefile
usr/src/lib/libzoneinfo_pymod/libzoneinfo.c
usr/src/pkgdefs/Makefile
usr/src/pkgdefs/SUNWdistro-const/prototype_com
usr/src/pkgdefs/SUNWinstall/prototype_com
usr/src/pkgdefs/SUNWtext-install/Makefile
usr/src/pkgdefs/SUNWtext-install/depend
usr/src/pkgdefs/SUNWtext-install/prototype_com
usr/src/pkgdefs/SUNWtext-install/prototype_i386
usr/src/pkgdefs/SUNWtext-install/prototype_sparc
usr/src/tools/env/install.pylintrc
--- a/usr/src/Makefile.master	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/Makefile.master	Tue Mar 16 14:07:17 2010 -0700
@@ -68,6 +68,8 @@
 GENCAT=			/usr/bin/gencat
 XGETTEXT=		xgettext
 XGETFLAGS=		-c TRANSLATION_NOTE
+GNUXGETTEXT=		/usr/gnu/bin/xgettext
+GNUXGETFLAGS=		--keyword=_ --strict --no-location --omit-header
 CSTYLE=			cstyle -pP
 
 # Reference paths for ON
@@ -84,6 +86,7 @@
 ROOTDC_AI=		$(ROOTDC)/auto_install
 ROOTDC_DOC=		$(ROOTDOC)/distro_const
 ROOTDC_SLIM=		$(ROOTDC)/slim_cd
+ROOTDC_TM=		$(ROOTDC)/text_install
 ROOTDC_VMC=		$(ROOTDC)/vmc
 ROOTDOC=		$(ROOT)/usr/share/doc
 ROOTAI_DOC=		$(ROOTDOC)/auto_install
@@ -99,9 +102,13 @@
 ROOTPYTHONVENDORINSTALLAI=	$(ROOTPYTHONVENDORINSTALL)/auto_install
 ROOTPYTHONVENDORINSTALLBEADM=	$(ROOTPYTHONVENDORINSTALL)/beadm
 ROOTPYTHONVENDORINSTALLDC=	$(ROOTPYTHONVENDORINSTALL)/distro_const
+ROOTPYTHONVENDORINSTALLTI=	$(ROOTPYTHONVENDORINSTALL)/text_install
+ROOTPYTHONVENDORINSTALLPROF=	$(ROOTPYTHONVENDORINSTALL)/profile
 ROOTAUTOINST=		$(ROOT)/usr/share/auto_install
 ROOTSBIN=		$(ROOT)/sbin
 ROOTUSRBIN=		$(ROOT)/usr/bin
+ROOTUSRSHARE=		$(ROOT)/usr/share
+ROOTUSRSHARETI=		$(ROOTUSRSHARE)/text-install
 ROOTUSRLIB=		$(ROOT)/usr/lib
 ROOTUSRLIBMSGS=		$(ROOTUSRLIB)/locale/C/LC_MESSAGES
 ROOTUSRSBIN=		$(ROOT)/usr/sbin
--- a/usr/src/README	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/README	Tue Mar 16 14:07:17 2010 -0700
@@ -39,6 +39,7 @@
  3. Install required IPS packages:
     * SUNWzoneint
     * SUNWswig
+    * SUNWgnu-gettext
     To get these packages, run "pfexec pkg install <package>"
 
  4. Install required SVr4 packages:
--- a/usr/src/Targetdirs	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/Targetdirs	Tue Mar 16 14:07:17 2010 -0700
@@ -64,7 +64,10 @@
 	/usr/lib/python2.6/vendor-packages/osol_install/auto_install \
 	/usr/lib/python2.6/vendor-packages/osol_install/beadm \
 	/usr/lib/python2.6/vendor-packages/osol_install/distro_const \
+	/usr/lib/python2.6/vendor-packages/osol_install/profile \
+	/usr/lib/python2.6/vendor-packages/osol_install/text_install \
 	/usr/sbin \
+	/usr/share/auto_install \
 	/usr/share/distro_const \
 	/usr/share/distro_const/auto_install \
 	/usr/share/distro_const/slim_cd \
@@ -77,7 +80,7 @@
 	/usr/share/man \
 	/usr/share/man/man1m \
 	/usr/share/man/man4 \
-	/usr/share/auto_install \
+	/usr/share/text-install \
 	/usr/snadm \
 	/usr/snadm/bin 
 
--- a/usr/src/cmd/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -31,7 +31,7 @@
 include $(SRC)/Makefile.master
 
 SUBDIRS= auto-install gui-install installadm rbac slim-install
-PYTHONSUBDIRS= ai-webserver beadm distro_const
+PYTHONSUBDIRS= ai-webserver beadm distro_const text-install
 TOOLSSUBDIRS= install-tools
 
 .PARALLEL:
--- a/usr/src/cmd/Makefile.cmd	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/Makefile.cmd	Tue Mar 16 14:07:17 2010 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 include $(SRC)/Makefile.master
@@ -28,6 +28,7 @@
 FILEMODE = 0755
 
 # Definitions of common installation directories
+ROOTADMINBIN	= $(ROOT)/usr/snadm/bin
 ROOTEXECATTR	= $(ROOT)/etc/security/exec_attr.d
 ROOTLIBSVCMETHOD	= $(ROOT)/lib/svc/method
 ROOTLIBSVCSHARE	= $(ROOT)/lib/svc/share
--- a/usr/src/cmd/Makefile.targ	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/Makefile.targ	Tue Mar 16 14:07:17 2010 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -66,6 +66,9 @@
 $(ROOTMANSYSINS)/%: %
 	$(INS.file)
 
+$(ROOTUSRLIBMSGS)/%: %
+	$(INS.file)
+
 $(ROOTPYTHONVENDOR):
 	$(INS.dir)
 
@@ -81,6 +84,12 @@
 $(ROOTPYTHONVENDORINSTALLAI):
 	$(INS.dir)
 
+$(ROOTPYTHONVENDORINSTALLPROF):
+	$(INS.dir)
+
+$(ROOTPYTHONVENDORINSTALLTI):
+	$(INS.dir)
+
 $(ROOTSBIN)/%: %
 	$(INS.file)
 
@@ -103,6 +112,12 @@
 $(ROOTPYTHONVENDORINSTALLAI)/%: %
 	$(CP_P.file)
 
+$(ROOTPYTHONVENDORINSTALLTI)/%: %
+	$(CP_P.file)
+
+$(ROOTPYTHONVENDORINSTALLPROF)/%: %
+	$(CP_P.file)
+
 $(ROOTDC):
 	$(INS.dir)
 
@@ -115,6 +130,12 @@
 $(ROOTDC_SLIM)/%: %
 	$(INS.file)
 
+$(ROOTDC_TM):
+	$(INS.dir)
+
+$(ROOTDC_TM)/%: %
+	$(INS.file)
+
 $(ROOTDC_AI):
 	$(INS.dir)
 
@@ -139,6 +160,9 @@
 $(ROOTUSRSBIN)/%: %
 	$(INS.file)
 
+$(ROOTUSRSHARETI)/%: %
+	$(INS.file)
+
 $(ROOTUSRLIBINSTALLADM)/%: %
 	$(INS.file)
 
--- a/usr/src/cmd/distro_const/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/distro_const/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -31,7 +31,7 @@
 clobber:=	TARGET=	clobber
 install:=	TARGET=	install
 
-SUBDIRS=	utils slim_cd auto_install docs vmc
+SUBDIRS=	utils slim_cd auto_install text_install docs vmc
 
 PROGS=		distro_const
 
--- a/usr/src/cmd/distro_const/auto_install/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/distro_const/auto_install/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -27,8 +27,8 @@
 include ../../Makefile.cmd
 
 all:=           TARGET= all
-clean:=         TARGET= clean
-clobber:=       TARGET= clobber
+clean:=           TARGET= clean
+clobber:=           TARGET= clobber
 install:=       TARGET= install
 
 PYMODULES=	ai_plat_setup.py
@@ -39,24 +39,18 @@
 			ai_x86_image.xml \
 			ai_sparc_image.xml \
 			ai_boot_archive_configure \
-			ai_post_boot_archive_pkg_image_mod \
-			ai_pre_boot_archive_pkg_image_mod \
-			$(PYMODULES)
+			ai_pre_boot_archive_pkg_image_mod
 
 ROOT_AUTOINSTALL_FILES=	$(AUTOINSTALL_FILES:%=$(ROOTDC_AI)/%)
 
-all:		python	
-
-clean:
-		$(RM) $(PYCMODULES)
-
-clobber: 	clean
+all:
 
 install:	all .WAIT $(ROOTDC) \
 		$(ROOTDC_AI) \
 		$(ROOT_AUTOINSTALL_FILES)
 
-python:	
-		$(PYTHON) -m compileall -l $(@D)
+clean:
+
+clobber:
 
 include ../../Makefile.targ
--- a/usr/src/cmd/distro_const/auto_install/ai_plat_setup.py	Mon Mar 15 11:50:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +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 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-""" ai_plat_setup
-
- Platform specific customizations for sparc
-
- To be done before post_boot_archive_pkg_image_mod gets called.
-
-"""
-
-import os
-import sys
-from osol_install.distro_const.dc_defs import BA_FILENAME_SUN4U
-from osol_install.distro_const.dc_defs import BA_FILENAME_SUN4V
-from osol_install.distro_const.dc_defs import BA_FILENAME_X86
-from osol_install.distro_const.dc_defs import BA_FILENAME_AMD64
-
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Main
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-""" Platform specific customizations for sparc.
-
-Args:
-  MFEST_SOCKET: Socket needed to get manifest data via ManifestRead object
-
-  PKG_IMG_PATH: Package image area mountpoint
-
-  TMP_DIR: Temporary directory (not used)
-
-  BA_BUILD: Area where boot archive is put together.  (not used)
-
-  MEDIA_DIR: Area where the media is put. (not used)
-
-  KERNEL_ARCH: Machine type for archive
-
-Note: This assumes a populated pkg_image area exists at the location
-	${PKG_IMG_PATH}
-
-"""
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-if (len(sys.argv) != 7): # Don't forget sys.argv[0] is the script itself.
-    raise Exception, (sys.argv[0] + ": Requires 6 args:\n" +
-                                    "    Reader socket, pkg_image area, " +
-                                    "temp dir,\n" +
-                                    "    boot archive build area, " +
-                                    "media area, machine type.")
-
-# collect input arguments from what this script sees as a commandline.
-PKG_IMG_PATH = sys.argv[2]	# package image area mountpoint
-KERNEL_ARCH = sys.argv[6]	# Machine type for this archive
-
-if KERNEL_ARCH == "sparc":
-    # Create the symlink from sun4v/boot_archive to sun4u/boot_archive
-    # The sun4u/boot_archive is the real boot_archive. We're using
-    # the same boot_archive for sun4v as sun4u.
-    try:
-        os.symlink("../.." + BA_FILENAME_SUN4U,
-                   PKG_IMG_PATH + BA_FILENAME_SUN4V)
-    except OSError, (errno, strerror):
-        print >> sys.stderr, "Error creating symlink for sun4v boot_archive"
-        raise
--- a/usr/src/cmd/distro_const/auto_install/ai_post_boot_archive_pkg_image_mod	Mon Mar 15 11:50:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-#!/bin/ksh
-#
-# 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 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-# =============================================================================
-# =============================================================================
-# ai_post_boot_archive_pkg_image_mod
-#
-# Customizations to the package image area after boot archive construction completes
-# Auto-install specific.
-# =============================================================================
-# =============================================================================
-
-
-# Define a few commands.
-RM=/usr/bin/rm
-MV=/usr/bin/mv
-CP=/usr/bin/cp
-LN=/usr/bin/ln
-FIND=/usr/bin/find
-XARGS=/usr/bin/xargs
-UNAME=/usr/bin/uname
-
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Main
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Customizations to the package image area after boot archive construction
-# completes.
-# 
-# Args:
-#   MFEST_SOCKET: Socket needed to get manifest data via ManifestRead
-#		object (not used)
-#
-#   PKG_IMG_PATH: Package image area
-#
-#   TMP_DIR: Temporary directory to contain the boot archive file (not used)
-#
-#   BA_BUILD: Area where boot archive is put together (not used)
-#
-#   MEDIA_DIR: Area where the media is put. (Not used)
-# 
-# Note: This assumes a populated pkg_image area exists at the location
-#		${PKG_IMG_PATH} and that the boot archive has been built.
-#
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-if [ "$#" != "5" ] ; then
-	print -u2 "Usage: $0: Requires 5 args:"
-	print -u2 "    Reader socket, pkg_image area, tmp_dir,"
-	print -u2 "    boot archive build area, media area"
-	exit 1
-fi
-
-PKG_IMG_PATH=$2
-if [ ! -d $PKG_IMG_PATH ] ; then
-	print -u2 "$0: Image package area $PKG_IMG_PATH is not valid"
-	exit 1
-fi
-
-# Platform only needs to contain the kernel and boot_archive for x86 and
-# in the case of a sparc image, wanboot and the boot_archive.
-initial_cwd=`pwd`
-if [ -d ${PKG_IMG_PATH}/platform ] ; then
-    cd ${PKG_IMG_PATH}/platform
-    if [ `$UNAME -p` == "sparc" ] ; then
-        $FIND . -type f -a ! -name wanboot -a ! -name boot_archive | $XARGS \
-            $RM -f
-        cd ${PKG_IMG_PATH}
-        ${MV} ${PKG_IMG_PATH}/platform ${PKG_IMG_PATH}/boot
-	${LN} -s boot/platform platform
-    else
-        $FIND . -type f -a ! -name unix -a ! -name boot_archive | $XARGS $RM -f
-        # GRUB does not understand symlinks, so make copies
-        cd ${PKG_IMG_PATH}
-        ${CP} -r ${PKG_IMG_PATH}/platform ${PKG_IMG_PATH}/boot
-    fi
-fi
-cd ${initial_cwd}
-
-exit 0
--- a/usr/src/cmd/distro_const/auto_install/ai_sparc_image.xml	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/distro_const/auto_install/ai_sparc_image.xml	Tue Mar 16 14:07:17 2010 -0700
@@ -104,11 +104,10 @@
 						name="ai-ba-config"
 						message="Auto Install boot archive configuration"/>
 				</script>
-				<script name="/usr/share/distro_const/auto_install/ai_plat_setup.py">
+				<script name="/usr/share/distro_const/plat_setup.py">
 					<checkpoint
-						name="ai-plat-setup"
+						name="plat-setup"
 						message="Platform specific setup"/>
-					<argslist>"sparc"</argslist>
 				</script>
 				<script name="/usr/share/distro_const/boot_archive_archive.py">
 					<checkpoint
@@ -116,10 +115,10 @@
 						message="Boot archive archiving"/>
 					<argslist>"sparc"</argslist>
 				</script>
-				<script name="/usr/share/distro_const/auto_install/ai_post_boot_archive_pkg_image_mod">
+				<script name="/usr/share/distro_const/post_boot_archive_pkg_image_mod_custom">
 					<checkpoint
-						name="ai-post-mod"
-						message="Auto-Install post boot archive image area modification"/>
+						name="post-mod-custom"
+						message="Post boot archive image area custom modification"/>
 				</script>
 				<script name="/usr/share/distro_const/post_boot_archive_pkg_image_mod">
 					<checkpoint
--- a/usr/src/cmd/distro_const/auto_install/ai_x86_image.xml	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/distro_const/auto_install/ai_x86_image.xml	Tue Mar 16 14:07:17 2010 -0700
@@ -104,12 +104,6 @@
 						name="ai-ba-config"
 						message="Auto Install boot archive configuration"/>
 				</script>
-				<script name="/usr/share/distro_const/auto_install/ai_plat_setup.py">
-					<checkpoint
-                                                name="ai-plat-setup"
-                                                message="Platform specific setup"/>
-					<argslist>"x86"</argslist>
-				</script>
 				<script name="/usr/share/distro_const/boot_archive_archive.py">
 					<checkpoint
 						name="ba-arch"
@@ -123,10 +117,10 @@
 					<argslist>"x86"</argslist>
 				</script>
 
-				<script name="/usr/share/distro_const/auto_install/ai_post_boot_archive_pkg_image_mod">
+				<script name="/usr/share/distro_const/post_boot_archive_pkg_image_mod_custom">
 					<checkpoint
-						name="ai-post-mod"
-						message="Auto-Install post boot archive image area modification"/>
+						name="post-mod-custom"
+						message="Post boot archive image area custom modification"/>
 				</script>
 				<script name="/usr/share/distro_const/grub_setup.py">
 					<checkpoint
--- a/usr/src/cmd/distro_const/slim_cd/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/distro_const/slim_cd/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -37,8 +37,7 @@
 		slim_cd_x86.xml \
 		all_lang_slim_cd_x86.xml \
 		slimcd_pre_boot_archive_pkg_image_mod \
-		slimcd_post_boot_archive_pkg_image_mod \
-		slimcd_gen_cd_content
+		slimcd_post_boot_archive_pkg_image_mod
 		
 ROOTSLIMCD_FILES=	$(SLIMCD_FILES:%=$(ROOTDC_SLIM)/%)
 
--- a/usr/src/cmd/distro_const/slim_cd/all_lang_slim_cd_x86.xml	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/distro_const/slim_cd/all_lang_slim_cd_x86.xml	Tue Mar 16 14:07:17 2010 -0700
@@ -138,10 +138,10 @@
 						"usr_zlib_compression=lzma"
 					</argslist>
 				</script>
-				<script name="/usr/share/distro_const/slim_cd/slimcd_gen_cd_content">
+				<script name="/usr/share/distro_const/gen_cd_content">
 					<checkpoint
-						name="gen-slim-cont"
-						message="Generate Slim CD image content list"/>
+						name="gen-cd-cont"
+						message="Generate CD image content list"/>
 				</script>
 				<script name="/usr/share/distro_const/create_iso">
 					<checkpoint
--- a/usr/src/cmd/distro_const/slim_cd/slim_cd_x86.xml	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/distro_const/slim_cd/slim_cd_x86.xml	Tue Mar 16 14:07:17 2010 -0700
@@ -138,10 +138,10 @@
 						"usr_zlib_compression=gzip"
 					</argslist>
 				</script>
-				<script name="/usr/share/distro_const/slim_cd/slimcd_gen_cd_content">
+				<script name="/usr/share/distro_const/gen_cd_content">
 					<checkpoint
-						name="gen-slim-cont"
-						message="Generate Slim CD image content list"/>
+						name="gen-cd-cont"
+						message="Generate CD image content list"/>
 				</script>
 				<script name="/usr/share/distro_const/create_iso">
 					<checkpoint
--- a/usr/src/cmd/distro_const/slim_cd/slimcd_gen_cd_content	Mon Mar 15 11:50:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-#!/bin/ksh
-#
-# 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 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Main
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# slimcd_gen_cd_content
-#
-# Generate the list of files that are part of the Slim Live CD image.
-# The result will be stored in the file .livecd-cdrom-content in the
-# root of the Live CD.
-#
-# The content of the .livecd-cdrom-content file will be used by the
-# Transfer Module to determine what files are part of the Slim Live CD image.
-# The transfer module will ignore all other files on the CD/DVD that
-# are not in the .livecd-cdrom-content file
-#
-# This finalizer script must be placed immediately before the finalizer
-# script to create the ISO file for the Live CD, otherwise, content
-# of the live cd might get modified further, and the content list might
-# not be accurate.
-#
-# The following files will NOT be included in the .livecd-cdrom-content file
-#
-# 1) *.zlib
-# 2) .livecd-cdrom-content
-# 3) .image_info
-# 
-# ==========================================================================
-# Args:
-#   MFEST_SOCKET: Socket needed to get manifest data via ManifestRead object
-#	(not used)
-#
-#   PKG_IMG_PATH: Package image area
-#
-#   TMP_DIR: Temporary directory to contain the boot archive file (not used)
-#
-#   BA_BUILD: Area where boot archive is put together (not used)
-#
-#   MEDIA_DIR: Area where the media is put (not used)
-#
-# Of these automatically-passed variables, only the PKG_IMG_PATH is actually
-# used.
-#
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-if [ "$#" != "5" ] ; then
-	print -u2 "Usage: $0: Requires 5 args:"
-	print -u2 "    Reader socket, pkg_image area, tmp dir,"
-	print -u2 "    boot archive build area, media area"
-	exit 1
-fi
-
-PKG_IMG_PATH=$2
-if [ ! -d ${PKG_IMG_PATH} ] ; then
-	print -u2 "$0: Image package area $PKG_IMG_PATH is not valid"
-	exit 1
-fi
-
-FIND=/usr/bin/find
-CD=cd	#use the "cd" built-in to the shell
-
-IMG_CONTENT_FILE=".livecd-cdrom-content"
-IMG_INFO_FILE=".image_info"
-BOOT_ARCHIVE_BASE="boot_archive"
-
-#
-# The package image area is the "root" of the live CD
-#
-${CD} ${PKG_IMG_PATH}
-if [ "$?" != "0" ] ; then
-	print -u2 "$0: unable to change into ${PKG_IMG_PATH}."
-	exit 1
-fi
-
-${FIND} . ! \( -name '*.zlib' -o -name ${IMG_INFO_FILE} \
-	-o -name ${IMG_CONTENT_FILE} -o -name ${BOOT_ARCHIVE_BASE} \) -print \
-	> ${IMG_CONTENT_FILE}
-
-if [ "$?" != "0" ] ; then
-	print -u2 "$0:  there's an error generating the image content list."
-	exit 1
-fi
-
-exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/text_install/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,52 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../../Makefile.cmd
+
+all:=           TARGET= all
+clean:=         TARGET= clean
+clobber:=         TARGET= clobber
+install:=       TARGET= install
+
+TM_FILES=	text_install_x86_iso.sort \
+		text_live.xml \
+		text_mode_sparc.xml \
+		text_mode_x86.xml \
+		tm_pre_boot_archive_pkg_image_mod
+		
+ROOTTM_FILES=	$(TM_FILES:%=$(ROOTDC_TM)/%)
+
+all:
+
+install:	all .WAIT $(ROOTDC) \
+		$(ROOTDC_TM) \
+		$(ROOTTM_FILES)
+
+clean:
+
+clobber:
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/text_install/text_live.xml	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,121 @@
+<?xml version='1.0'?>
+<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
+<!--
+    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 2010 Sun Microsystems, Inc.  All rights reserved.
+    Use is subject to license terms.
+
+    Service profile customization for Text Installer image
+-->
+<service_bundle type='profile' name='text_live'
+	 xmlns:xi='http://www.w3.org/2003/XInclude' >
+
+  <!--
+      svc.startd(1M) services
+  -->
+
+  <service name='system/hal' version='1' type='service'>
+    <instance name='default' enabled='true'/>
+  </service>
+  <service name='system/postrun' version='1' type='service'>
+    <instance name='default' enabled='false'/>
+  </service>
+  <service name='system/filesystem/zfssnap-roleadd' version='1' type='service'>
+    <instance name='default' enabled='false'/>
+  </service>
+  <service name='network/nfs/server' version='1' type='service'>
+    <instance name='default' enabled='false'/>
+  </service>
+  <service name='network/physical' version='1' type='service'>
+      <instance name='default' enabled='false'/>
+      <instance name='nwam' enabled='true'/>
+  </service>
+  <service name='network/rpc/gss' version='1' type='service'>
+      <instance name='default' enabled='false'/>
+  </service>
+  <service name='network/sendmail-client' version='1' type='service'>
+    <instance name='default' enabled='false'/>
+  </service>
+  <service name='network/shares/group' version='1' type='service'>
+    <instance name='default' enabled='false'/>
+    <instance name='zfs' enabled='false'/>
+  </service>
+  <service name='network/tnctl' version='1' type='service'>
+    <instance name='default' enabled='false'/>
+  </service>
+  <service name='network/inetd-ugrade' version='1' type='service'>
+    <instance name='default' enabled='false'/>
+  </service>
+  <service name='system/filesystem/rmvolmgr' version='1' type='service'>
+    <instance name='default' enabled='true'/>
+  </service>
+  <service name='application/management/sma' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='application/management/seaport' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='application/management/snmpdx' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='application/print/cleanup' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='application/print/ipp-listener' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='application/print/ppd-cache-update' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='system/basicreg' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='platform/i86pc/kdmconfig' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='application/stosreg' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='network/security/ktkt_warn' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='network/dns/multicast' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+  <service name='application/pkg/update' version='1' type='service'>
+    <instance name='default' enabled='false' />
+  </service>
+
+  <!--
+	Text mode menu
+  -->
+  <service name='system/install-setup' version='1' type='service'>
+    <instance name='default' enabled='true'/>
+  </service>
+
+  <!--
+	Disable console login by default
+  -->
+  <service name='system/console-login' version='1' type='service'>
+    <instance name='default' enabled='false'/>
+  </service>
+
+</service_bundle>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/text_install/text_mode_sparc.xml	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,761 @@
+<!--
+    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 2010 Sun Microsystems, Inc.  All rights reserved.
+    Use is subject to license terms.
+
+    XML specification for building the limited language OpenSolaris
+    Text Mode Installer iso and usb image
+-->
+
+<distribution name="OpenSolaris_Text_Installer_SPARC">
+	<distro_constr_params>
+		<!--
+		     Where to build. This can be a zfs dataset or a mountpoint.
+		     The area will be created if it doesn't exist. If the build_area
+		     is not a zfs dataset or mountpoint, checkpointing will not
+		     be enabled.
+		-->
+		<build_area>rpool/dc</build_area>
+		<distro_constr_flags>
+			<!--
+			     Controls whether the DC should stop
+			     if there is an error when the DC is running 
+			-->
+			<stop_on_error>true</stop_on_error>
+			<!--
+			     You can specify the step to resume the
+			     build from here with the resume_from
+			     attribute field of checkpoint_enable.
+			     This value will be overridden by
+			     the command line if the -r flag is used.
+			     Valid values are step
+			     numbers or name
+			-->
+			<checkpoint_enable>
+				<!--
+				     true implies Checkpointing is enabled
+				-->
+				true
+			</checkpoint_enable>
+		</distro_constr_flags>
+		<output_image>
+			<!--
+			     List of finalizer scripts to be run. They are used
+			     to customize the image and will be run in the
+			     order listed. The name of the checkpoint to
+			     be created when this script is run is required.
+			     The checkpoint message is displayed when the
+			     step is run and is optional.
+			     There are 5 standard arguments that are passed to
+			     every finalizer script (manifest socket, pkg_image path,
+			     tmp dir, boot archive build area, media dir). You may also
+			     specify additional arguments (arg6+) in the argslist.
+			     This argslist is a whitespace-separated list of double
+			     quoted strings.
+			-->
+			<finalizer>
+				<script name="/usr/share/distro_const/im_pop.py">
+					<checkpoint
+						name="im-pop"
+						message="Image area creation"/>
+				</script>
+				<script name="/usr/share/distro_const/pre_boot_archive_pkg_image_mod.py">
+					<checkpoint
+						name="im-mod"
+						message="Image area modifications"/>
+				</script>
+				<script name="/usr/share/distro_const/text_install/tm_pre_boot_archive_pkg_image_mod">
+					<checkpoint
+						name="tm-im-mod"
+						message="Text mode Image area Modifications"/>
+				</script>
+				<script name="/usr/share/distro_const/boot_archive_initialize.py">
+					<checkpoint
+						name="ba-init"
+						message="Boot archive initialization"/>
+				</script>
+				<script name="/usr/share/distro_const/boot_archive_configure">
+					<checkpoint
+						name="ba-config"
+						message="Boot archive configuration"/>
+					<argslist>
+						".textinstall"
+					</argslist>
+				</script>
+				<script name="/usr/share/distro_const/plat_setup.py">
+					<checkpoint
+						name="plat-setup"
+						message="Platform specific setup"/>
+				</script>
+				<script name="/usr/share/distro_const/boot_archive_archive.py">
+					<checkpoint
+						name="ba-arch"
+						message="Boot archive archiving"/>
+					<argslist>"sparc"</argslist>
+				</script>
+				<script name="/usr/share/distro_const/post_boot_archive_pkg_image_mod_custom">
+					<checkpoint
+						name="post-mod-custom"
+						message="Post boot archive image area custom modification"/>
+				</script>
+				<script name="/usr/share/distro_const/post_boot_archive_pkg_image_mod">
+					<checkpoint
+						name="post-mod"
+						message="Post boot archive image area modification"/>
+					<argslist>
+						"usr_zlib_compression=lzma"
+					</argslist>
+				</script>
+				<script name="/usr/share/distro_const/gen_cd_content">
+					<checkpoint
+						name="gen-cd-cont"
+						message="Generate CD image content list"/>
+				</script>
+				<script name="/usr/share/distro_const/create_iso">
+					<checkpoint
+						name="iso"
+						message="ISO image creation"/>
+				</script>
+			</finalizer>
+			<boot_archive>
+				<!--
+				     If/how to compress the boot archive. Valid
+				     types are gzip and none
+				-->
+				<compression type="gzip" level="9"/>
+				<!--
+				    SMF service profiles to apply to the 
+				    boot archive. If the "use_build_sys_file" 
+				    attribute is set to true, the build
+				    system's copy of the file is used.  If not 
+				    specified, or "use_build_sys_file" is set 
+				    to false, the image's copy of the file 
+				    is used.
+
+				    Service profiles will be applied to the 
+				    root archive in the order listed.
+				-->
+				<smf_service_profile>
+					<profile path="/var/svc/profile/generic_limited_net.xml"
+					         use_build_sys_file="false"/>
+					<profile path="/usr/share/distro_const/generic_live.xml"
+					         use_build_sys_file="true"/>
+					<profile path="/usr/share/distro_const/text_install/text_live.xml"
+					         use_build_sys_file="true"/>
+					<profile path="/var/svc/profile/ns_files.xml"
+					         use_build_sys_file="false"/>
+				</smf_service_profile>
+			</boot_archive>
+		</output_image>
+	</distro_constr_params>
+	<img_params>
+		<!--
+		     The preferred authority to install packages into the
+		     pkg_image area from.
+		     The default url is: http://pkg.opensolaris.org/release
+		     The default authname is opensolaris.org
+		-->
+		<pkg_repo_default_authority>
+			<main
+				url="http://pkg.opensolaris.org/release"
+				authname="opensolaris.org"/>
+			<!--
+			     If you want to use one or more  mirrors that are
+			     setup for the authority, specify the urls here.
+			-->
+			<!--
+			     Uncomment before using
+			<mirror url="" />
+			-->
+		</pkg_repo_default_authority>
+		<!--
+		     Any additional non-preferred authorities to pull packages
+		     from should be specified here. Multiple additional
+		     authorities may be specified.
+		     If you want to use one or more  mirrors that are
+		     setup for the authority, specify the urls here.
+		-->
+		<!--
+		     Uncomment before using.
+		<pkg_repo_addl_authority>
+			<main
+				url=""
+				authname=""/>
+			<mirror url="" />
+		</pkg_repo_addl_authority>
+		-->
+		<!--
+		     The default preferred authority to be used by the system
+		     after it has been installed.
+		     The default url is: http://pkg.opensolaris.org/release
+		     The default authname is opensolaris.org
+		     If you want to use one or more  mirrors that are
+		     setup for the authority, specify the urls here.
+		-->
+		<post_install_repo_default_authority>
+			<main
+				url="http://pkg.opensolaris.org/release"
+				authname="opensolaris.org"/>
+			<!--
+			     Uncomment before using.
+			<mirror url="" />
+			-->
+		</post_install_repo_default_authority>
+		<!--
+		     Any additional non-preferred authorities to use after the
+		     system has been installed. Multiple additional authorities
+		     may be specified.
+		     If you want to use one or more  mirrors that are
+		     setup for the authority, specify the urls here.
+		-->
+		<!--
+		    Uncomment before using.
+		<post_install_repo_addl_authority>
+			<main
+				url=""
+				authname=""/>
+			<mirror url="" />
+		</post_install_repo_addl_authority>
+		-->
+		<!--
+		     list of packages used to form the installed image
+		-->
+		<packages>
+			<!--
+			     Due to dependency issues, SUNWcsd and SUNWcs
+			     must be listed first in the package list,
+			     and SUNWcsd must precede SUNWcs
+			-->
+			<!--
+			    By default the latest build available, in the
+			    specified IPS repository, is installed.
+			    If another build is required, the build number has
+			    to be appended to the 'entire' package in following
+			    form:
+
+			    <pkg_name="[email protected]#/>
+			-->
+			<pkg name="entire"/>
+			<pkg name="SUNWcsd"/>
+			<pkg name="SUNWcs"/>
+			<pkg name="SUNW1394"/>
+			<pkg name="SUNWa2ps"/>
+			<pkg name="SUNWacc"/>
+			<pkg name="SUNWaalib"/>
+			<pkg name="SUNWadmap"/>
+			<pkg name="SUNWadmlib-sysid"/>
+			<pkg name="SUNWadmr"/>
+			<pkg name="SUNWafe"/>
+			<pkg name="SUNWastfb"/>
+			<pkg name="SUNWastfbcf"/>
+			<pkg name="SUNWatfs"/>
+			<pkg name="SUNWbart"/>
+			<pkg name="SUNWbash"/>
+			<pkg name="SUNWbeadm"/>
+			<pkg name="SUNWbge"/>
+			<pkg name="SUNWbindc"/>
+			<pkg name="SUNWbip"/>
+			<pkg name="SUNWbridge"/>
+			<pkg name="SUNWbtool"/>
+			<pkg name="SUNWbzip"/>
+			<pkg name="SUNWcakr"/>
+			<pkg name="SUNWcar"/>
+			<pkg name="SUNWced"/>
+			<pkg name="SUNWcfcl"/>
+			<pkg name="SUNWcfpl"/>
+			<pkg name="SUNWchxge"/>
+			<pkg name="SUNWckr"/>
+			<pkg name="SUNWcnetr"/>
+			<pkg name="SUNWcpc"/>
+			<pkg name="SUNWcpcu"/>
+			<pkg name="SUNWcpp"/>
+			<pkg name="SUNWcpr"/>
+			<pkg name="SUNWcsl"/>
+			<pkg name="SUNWcti2"/>
+			<pkg name="SUNWcups-libs"/>
+			<pkg name="SUNWcurl"/>
+			<pkg name="SUNWcvc"/>
+			<pkg name="SUNWdbus"/>
+			<pkg name="SUNWdcs"/>
+			<pkg name="SUNWdistro-license-copyright"/>
+			<pkg name="SUNWdmfe"/>
+			<pkg name="SUNWdoc"/>
+			<pkg name="SUNWdrcr"/>
+			<pkg name="SUNWdrr"/>
+			<pkg name="SUNWdsd"/>
+			<pkg name="SUNWdscp"/>
+			<pkg name="SUNWdtrc"/>
+			<pkg name="SUNWdtrp"/>
+			<pkg name="SUNWefb"/>
+			<pkg name="SUNWefbcf"/>
+			<pkg name="SUNWefbw"/>
+			<pkg name="SUNWefc"/>
+			<pkg name="SUNWemlxs"/>
+			<pkg name="SUNWerid"/>
+			<pkg name="SUNWesu"/>
+			<pkg name="SUNWexpect"/>
+			<pkg name="SUNWfbc"/>
+			<pkg name="SUNWfchba"/>
+			<pkg name="SUNWfcip"/>
+			<pkg name="SUNWfcmdb"/>
+			<pkg name="SUNWfcoeu"/>
+			<pkg name="SUNWfcp"/>
+			<pkg name="SUNWfcprt"/>
+			<pkg name="SUNWfcsm"/>
+			<pkg name="SUNWfctl"/>
+			<pkg name="SUNWffilters"/>
+			<pkg name="SUNWfmd"/>
+			<pkg name="SUNWfppd"/>
+			<pkg name="SUNWfruid"/>
+			<pkg name="SUNWfruip"/>
+			<pkg name="SUNWfs"/>
+			<pkg name="SUNWfss"/>
+			<pkg name="SUNWftp"/>
+			<pkg name="SUNWfwdc"/>
+			<pkg name="SUNWfwdcu"/>
+			<pkg name="SUNWfwflash"/>
+			<pkg name="SUNWgawk"/>
+			<pkg name="SUNWgcmn"/>
+			<pkg name="SUNWged"/>
+			<pkg name="SUNWggrp"/>
+			<pkg name="SUNWgnu-coreutils"/>
+			<pkg name="SUNWgnu-diffutils"/>
+			<pkg name="SUNWgnu-findutils"/>
+			<pkg name="SUNWgnu-idn"/>
+			<pkg name="SUNWgnu-mp"/>
+			<pkg name="SUNWgnu-nano"/>
+			<pkg name="SUNWgnu-which"/>
+			<pkg name="SUNWgnutls"/>
+			<pkg name="SUNWgpch"/>
+			<pkg name="SUNWgrub"/>
+			<pkg name="SUNWgsed"/>
+			<pkg name="SUNWgtar"/>
+			<pkg name="SUNWgzip"/>
+			<pkg name="SUNWhal"/>
+			<pkg name="SUNWhmd"/>
+			<pkg name="SUNWhmdu"/>
+			<pkg name="SUNWhwdata"/>
+			<pkg name="SUNWhxge"/>
+			<pkg name="SUNWib"/>
+			<pkg name="SUNWibsdp"/>
+			<pkg name="SUNWibsdpib"/>
+			<pkg name="SUNWibsdpu"/>
+			<pkg name="SUNWidn"/>
+			<pkg name="SUNWidnl"/>
+			<pkg name="SUNWigb"/>
+			<pkg name="SUNWima"/>
+			<pkg name="SUNWimac"/>
+			<pkg name="SUNWinstall"/>
+			<pkg name="SUNWinstall-l10n"/>
+			<pkg name="SUNWinstall-libs"/>
+			<pkg name="SUNWinstall-test"/>
+			<pkg name="SUNWintgige"/>
+			<pkg name="SUNWiopc"/>
+			<pkg name="SUNWipc"/>
+			<pkg name="SUNWipf"/>
+			<pkg name="SUNWipkg"/>
+			<pkg name="SUNWipkg-brand"/>
+			<pkg name="SUNWipmi"/>
+			<pkg name="SUNWipoib"/>
+			<pkg name="SUNWippcore"/>
+			<pkg name="SUNWippl"/>
+			<pkg name="SUNWiscsi"/>
+			<pkg name="SUNWiscsitgt"/>
+			<pkg name="SUNWislcc"/>
+			<pkg name="SUNWiso-codes"/>
+			<pkg name="SUNWixgb"/>
+			<pkg name="SUNWixgbe"/>
+			<pkg name="SUNWkey"/>
+			<pkg name="SUNWkfb"/>
+			<pkg name="SUNWkfbcf"/>
+			<pkg name="SUNWkfbw"/>
+			<pkg name="SUNWkrb"/>
+			<pkg name="SUNWkvm"/>
+			<pkg name="SUNWlang-ar"/>
+			<pkg name="SUNWlang-be"/>
+			<pkg name="SUNWlang-bg"/>
+			<pkg name="SUNWlang-ca"/>
+			<pkg name="SUNWlang-common"/>
+			<pkg name="SUNWlang-cs"/>
+			<pkg name="SUNWlang-da"/>
+			<pkg name="SUNWlang-de"/>
+			<pkg name="SUNWlang-deDE"/>
+			<pkg name="SUNWlang-el"/>
+			<pkg name="SUNWlang-en"/>
+			<pkg name="SUNWlang-enUS"/>
+			<pkg name="SUNWlang-es"/>
+			<pkg name="SUNWlang-esES"/>
+			<pkg name="SUNWlang-et"/>
+			<pkg name="SUNWlang-fi"/>
+			<pkg name="SUNWlang-fr"/>
+			<pkg name="SUNWlang-frFR"/>
+			<pkg name="SUNWlang-he"/>
+			<pkg name="SUNWlang-hi"/>
+			<pkg name="SUNWlang-hr"/>
+			<pkg name="SUNWlang-hu"/>
+			<pkg name="SUNWlang-id"/>
+			<pkg name="SUNWlang-is"/>
+			<pkg name="SUNWlang-it"/>
+			<pkg name="SUNWlang-ja"/>
+			<pkg name="SUNWlang-ka"/>
+			<pkg name="SUNWlang-kk"/>
+			<pkg name="SUNWlang-ko"/>
+			<pkg name="SUNWlang-lt"/>
+			<pkg name="SUNWlang-lv"/>
+			<pkg name="SUNWlang-mk"/>
+			<pkg name="SUNWlang-ms"/>
+			<pkg name="SUNWlang-mt"/>
+			<pkg name="SUNWlang-nb"/>
+			<pkg name="SUNWlang-nl"/>
+			<pkg name="SUNWlang-nn"/>
+			<pkg name="SUNWlang-pl"/>
+			<pkg name="SUNWlang-pt"/>
+			<pkg name="SUNWlang-ptBR"/>
+			<pkg name="SUNWlang-ro"/>
+			<pkg name="SUNWlang-ru"/>
+			<pkg name="SUNWlang-sh"/>
+			<pkg name="SUNWlang-sk"/>
+			<pkg name="SUNWlang-sl"/>
+			<pkg name="SUNWlang-sq"/>
+			<pkg name="SUNWlang-sr"/>
+			<pkg name="SUNWlang-sv"/>
+			<pkg name="SUNWlang-th"/>
+			<pkg name="SUNWlang-tr"/>
+			<pkg name="SUNWlang-uk"/>
+			<pkg name="SUNWlang-vi"/>
+			<pkg name="SUNWlang-zhCN"/>
+			<pkg name="SUNWlang-zhHK"/>
+			<pkg name="SUNWlang-zhTW"/>
+			<pkg name="SUNWldom"/>
+			<pkg name="SUNWless"/>
+			<pkg name="SUNWlexpt"/>
+			<pkg name="SUNWlibC"/>
+			<pkg name="SUNWlibdaemon"/>
+			<pkg name="SUNWlibffi"/>
+			<pkg name="SUNWlibgcrypt"/>
+			<pkg name="SUNWlibgpg-error"/>
+			<pkg name="SUNWlibm"/>
+			<pkg name="SUNWlibms"/>
+			<pkg name="SUNWlibpcap"/>
+			<pkg name="SUNWlibpopt"/>
+			<pkg name="SUNWlibsasl"/>
+			<pkg name="SUNWlibsmbclient"/>
+			<pkg name="SUNWlibtasn1"/>
+			<pkg name="SUNWlibusb"/>
+			<pkg name="SUNWlibusbugen"/>
+			<pkg name="SUNWlldap"/>
+			<pkg name="SUNWloc"/>
+			<pkg name="SUNWltdl"/>
+			<pkg name="SUNWluxd"/>
+			<pkg name="SUNWluxl"/>
+			<pkg name="SUNWluxop"/>
+			<pkg name="SUNWluxopr"/>
+			<pkg name="SUNWlxml"/>
+			<pkg name="SUNWlxsl"/>
+			<pkg name="SUNWman"/>
+			<pkg name="SUNWman-l10n-ja"/>
+			<pkg name="SUNWmd"/>
+			<pkg name="SUNWmdb"/>
+			<pkg name="SUNWmkcd"/>
+			<pkg name="SUNWmpapi"/>
+			<pkg name="SUNWmpathadm"/>
+			<pkg name="SUNWmpsvplr"/>
+			<pkg name="SUNWmptsas"/>
+			<pkg name="SUNWmrsas"/>
+			<pkg name="SUNWmxfe"/>
+			<pkg name="SUNWmyri10ge"/>
+			<pkg name="SUNWncurses"/>
+			<pkg name="SUNWnet-snmp-core"/>
+			<pkg name="SUNWnet-snmp-utils"/>
+			<pkg name="SUNWn2cp"/>
+			<pkg name="SUNWnfsc"/>
+			<pkg name="SUNWnfss"/>
+			<pkg name="SUNWnis"/>
+			<pkg name="SUNWniumx"/>
+			<pkg name="SUNWntp"/>
+			<pkg name="SUNWnxge"/>
+			<pkg name="SUNWopenssl"/>
+			<pkg name="SUNWpacket"/>
+			<pkg name="SUNWp7zip"/>
+			<pkg name="SUNWpapi"/>
+			<pkg name="SUNWpcelx"/>
+			<pkg name="SUNWpciaccess"/>
+			<pkg name="SUNWpcmci"/>
+			<pkg name="SUNWpcre"/>
+			<pkg name="SUNWpcser"/>
+			<pkg name="SUNWpd"/>
+			<pkg name="SUNWperl-authen-pam"/>
+			<pkg name="SUNWperl-xml-parser"/>
+			<pkg name="SUNWperl584core"/>
+			<pkg name="SUNWperl584man"/>
+			<pkg name="SUNWperl584usr"/>
+			<pkg name="SUNWpicl"/>
+			<pkg name="SUNWpkgcmds"/>
+			<pkg name="SUNWpm"/>
+			<pkg name="SUNWpmcs"/>
+			<pkg name="SUNWpool"/>
+			<pkg name="SUNWpoold"/>
+			<pkg name="SUNWpowertop"/>
+			<pkg name="SUNWpppd"/>
+			<pkg name="SUNWpppdt"/>
+			<pkg name="SUNWpppg"/>
+			<pkg name="SUNWpr"/>
+			<pkg name="SUNWps"/>
+			<pkg name="SUNWpsdpr"/>
+			<pkg name="SUNWpsf"/>
+			<pkg name="SUNWpsm-ipp"/>
+			<pkg name="SUNWpsm-lpd"/>
+			<pkg name="SUNWpstl"/>
+			<pkg name="SUNWpython-cherrypy"/>
+			<pkg name="SUNWpython-lxml"/>
+			<pkg name="SUNWpython-mako"/>
+			<pkg name="SUNWpython-ply"/>
+			<pkg name="SUNWpython-pycurl"/>
+			<pkg name="SUNWpython-pyopenssl"/>
+			<pkg name="SUNWpython-twisted"/>
+			<pkg name="SUNWpython-xdg"/>
+			<pkg name="SUNWpython-zope-interface"/>
+			<pkg name="SUNWpyyaml24"/>
+			<pkg name="SUNWqfed"/>
+			<pkg name="SUNWqlc"/>
+			<pkg name="SUNWqlcu"/>
+			<pkg name="SUNWrcmdc"/>
+			<pkg name="SUNWrcmds"/>
+			<pkg name="SUNWrge"/>
+			<pkg name="SUNWrmvolmgr"/>
+			<pkg name="SUNWroute"/>
+			<pkg name="SUNWrpcib"/>
+			<pkg name="SUNWrsync"/>
+			<pkg name="SUNWsbp2"/>
+			<pkg name="SUNWsckm"/>
+			<pkg name="SUNWscsa1394"/>
+			<pkg name="SUNWsdcard"/>
+			<pkg name="SUNWses"/>
+			<pkg name="SUNWsfdr"/>
+			<pkg name="SUNWsfe"/>
+			<pkg name="SUNWsigcpp"/>
+			<pkg name="SUNWslim-utils"/>
+			<pkg name="SUNWsmapi"/>
+			<pkg name="SUNWsmbfs"/>
+			<pkg name="SUNWsmedia"/>
+			<pkg name="SUNWsmpd"/>
+			<pkg name="SUNWsndm"/>
+			<pkg name="SUNWsolnm"/>
+			<pkg name="SUNWsprot"/>
+			<pkg name="SUNWsqlite3"/>
+			<pkg name="SUNWssad"/>
+			<pkg name="SUNWssh"/>
+			<pkg name="SUNWsshcu"/>
+			<pkg name="SUNWsshd"/>
+			<pkg name="SUNWstc"/>
+			<pkg name="SUNWsudo"/>
+			<pkg name="SUNWTcl"/>
+			<pkg name="SUNWTiff"/>
+			<pkg name="SUNWTk"/>
+			<pkg name="SUNWtavor"/>
+			<pkg name="SUNWtcpd"/>
+			<pkg name="SUNWtecla"/>
+			<pkg name="SUNWter"/>
+			<pkg name="SUNWtexi"/>
+			<pkg name="system/install/text-install"/>
+			<pkg name="SUNWtftp"/>
+			<pkg name="SUNWtls"/>
+			<pkg name="SUNWtnetc"/>
+			<pkg name="SUNWtnetd"/>
+			<pkg name="SUNWtoo"/>
+			<pkg name="SUNWtop"/>
+			<pkg name="SUNWtpm"/>
+			<pkg name="SUNWts"/>
+			<pkg name="SUNWtss"/>
+			<pkg name="SUNWuacm"/>
+			<pkg name="SUNWudapl"/>
+			<pkg name="SUNWudaplt"/>
+			<pkg name="SUNWudf"/>
+			<pkg name="SUNWuedg"/>
+			<pkg name="SUNWuftdi"/>
+			<pkg name="SUNWugen"/>
+			<pkg name="SUNWuiu8"/>
+			<pkg name="SUNWuksp"/>
+			<pkg name="SUNWukspfw"/>
+			<pkg name="SUNWunzip"/>
+			<pkg name="SUNWuprl"/>
+			<pkg name="SUNWus"/>
+			<pkg name="SUNWusb"/>
+			<pkg name="SUNWusbs"/>
+			<pkg name="SUNWust"/>
+			<pkg name="SUNWuwb"/>
+			<pkg name="SUNWvim"/>
+			<pkg name="SUNWvr"/>
+			<pkg name="SUNWwbsup"/>
+			<pkg name="SUNWwget"/>
+			<pkg name="SUNWwsr2"/>
+			<pkg name="SUNWxcu4"/>
+			<pkg name="SUNWxge"/>
+			<pkg name="SUNWyge"/>
+			<pkg name="SUNWzfs"/>
+			<pkg name="SUNWzip"/>
+			<pkg name="SUNWzlib"/>
+			<pkg name="SUNWzone"/>
+			<pkg name="SUNWDTraceToolkit"/>
+		</packages>
+<!--
+     Items below this line are rarely configured
+-->
+		<!--
+		     If/how to compress the live image.
+		     type = compression algorithm to use for pkg.zlib and misc.zlib.
+		     Valid types are lzma, gzip, and none.
+		-->
+		<live_img_compression type="lzma"/>
+		<!--
+		     Indicate whether the IPS index should be generated for
+		     pkg install and uninstall.  The default is to not
+		     generate the IPS search index
+		-->
+		<generate_ips_search_index>
+			false
+		</generate_ips_search_index>
+		<!--
+		     Files and dirs to be included in the boot archive of all media
+		     delivered by this distribution. Boot archive contains the
+		     minimal list of contents in order to be able to
+		     boot and setup a running system. These files and dirs
+		     must exist in the pkg_image area.
+		-->
+		<boot_archive_contents>
+			<base_include type="file">usr/sbin/pmadm</base_include>
+			<base_include type="file">usr/sbin/prtconf</base_include>
+			<base_include type="file">usr/sbin/sparcv9/prtconf</base_include>
+			<base_include type="file">usr/sbin/lofiadm</base_include>
+			<base_include type="file">usr/sbin/devfsadm</base_include>
+			<base_include type="file">usr/sbin/modload</base_include>
+			<base_include type="file">usr/sbin/sparcv9/modload</base_include>
+			<base_include type="file">usr/sbin/mount</base_include>
+			<base_include type="file">usr/sbin/hostconfig</base_include>
+			<base_include type="file">usr/sbin/chroot</base_include>
+			<base_include type="file">usr/sbin/syslogd</base_include>
+			<base_include type="file">usr/sbin/svcadm</base_include>
+			<base_include type="file">usr/sbin/svccfg</base_include>
+			<base_include type="file">usr/sbin/df</base_include>
+			<base_include type="file">usr/bin/coreadm</base_include>
+			<base_include type="file">usr/bin/bash</base_include>
+			<base_include type="file">usr/bin/ksh</base_include>
+			<base_include type="file">usr/bin/cut</base_include>
+			<base_include type="file">usr/bin/sed</base_include>
+			<base_include type="file">usr/bin/mkdir</base_include>
+			<base_include type="file">usr/bin/more</base_include>
+			<base_include type="file">usr/bin/cat</base_include>
+			<base_include type="file">usr/bin/echo</base_include>
+			<base_include type="file">usr/bin/false</base_include>
+			<base_include type="file">usr/bin/grep</base_include>
+			<base_include type="file">usr/bin/ls</base_include>
+			<base_include type="file">usr/bin/rm</base_include>
+			<base_include type="file">usr/bin/svcprop</base_include>
+			<base_include type="file">usr/bin/true</base_include>
+			<base_include type="file">usr/bin/cd</base_include>
+			<base_include type="file">usr/bin/test</base_include>
+			<base_include type="file">usr/bin/sleep</base_include>
+			<base_include type="file">usr/bin/expr</base_include>
+			<base_include type="file">usr/bin/isaexec</base_include>
+			<base_include type="file">usr/bin/vi</base_include>
+			<base_include type="file">usr/bin/wget</base_include>
+			<base_include type="file">usr/has/bin/vi</base_include>
+			<base_include type="file">usr/lib/fs/hsfs/fstyp</base_include>
+			<base_include type="file">usr/lib/fs/hsfs/fstyp.so.1</base_include>
+			<base_include type="file">usr/lib/fs/hsfs/mount</base_include>
+			<base_include type="file">usr/lib/fs/tmpfs/mount</base_include>
+			<base_include type="file">usr/lib/fs/ufs/fstyp</base_include>
+			<base_include type="file">usr/lib/fs/ufs/fstyp.so.1</base_include>
+			<base_include type="file">usr/lib/fs/ufs/mount</base_include>
+			<base_include type="file">usr/lib/libfstyp.so.1</base_include>
+			<base_include type="file">usr/lib/platexec</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_audio_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_cfg_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_disk_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_fssnap_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_ieee1394_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_lofi_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_md_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_misc_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_port_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_ramdisk_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_sgen_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_tape_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_usb_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/linkmod/SUNW_zfs_link.so</base_include>
+			<base_include type="file">usr/lib/devfsadm/devfsadmd</base_include>
+			<base_include type="file">usr/lib/libm.so.2</base_include>
+			<base_include type="file">usr/lib/libm.so</base_include>
+			<base_include type="file">usr/lib/libfstyp.so</base_include>
+			<base_include type="file">usr/lib/libz.so</base_include>
+			<base_include type="file">usr/lib/libz.so.1</base_include>
+			<base_include type="file">usr/bin/sparcv9/ksh93</base_include>
+			<base_include type="file">usr/bin/sparcv7/ksh93</base_include>
+			<base_include type="file">usr/lib/isaexec</base_include>
+			<base_include type="file">usr/lib/libast.so.1</base_include>
+			<base_include type="file">usr/lib/libcmd.so.1</base_include>
+			<base_include type="file">usr/lib/libdll.so.1</base_include>
+			<base_include type="file">usr/lib/libshell.so.1</base_include>
+			<base_include type="file">usr/lib/libcrypt.so.1</base_include>
+			<base_include type="file">usr/lib/libmapmalloc.so.1</base_include>
+			<base_include type="file">usr/sfw/lib/libcrypto.so.0.9.8</base_include>
+			<base_include type="file">usr/sfw/lib/libssl.so.0.9.8</base_include>
+			<base_include type="file">usr/share/lib/xml/dtd/service_bundle.dtd.1</base_include>
+			<base_include type="file">var/sadm/install/admin/default</base_include>
+			<base_include type="file">var/sadm/system/admin/default_java</base_include>
+			<base_include type="file">var/sadm/install/contents</base_include>
+			<base_include type="file">var/adm/utmpx</base_include>
+			<base_include type="file">var/adm/wtmpx</base_include>
+			<base_include type="file">var/adm/aculog</base_include>
+			<base_include type="file">var/lib/postrun/postrun-runq</base_include>
+			<base_include type="file">var/lib/postrun/postrun</base_include>
+			<base_include type="file">var/log/postrun.log</base_include>
+			<base_include type="file">var/log/authlog</base_include>
+			<base_include type="file">var/log/syslog</base_include>
+			<base_include type="file">var/saf/zsmon/log</base_include>
+			<base_include type="file">var/spool/cron/crontabs/adm</base_include>
+			<base_include type="file">var/spool/cron/crontabs/root</base_include>
+			<base_include type="file">var/nis/NIS+LDAPmapping.template</base_include>
+			<base_include type="file">var/yp/aliases</base_include>
+			<base_include type="file">var/yp/nicknames</base_include>
+			<base_include type="dir">kernel</base_include>
+			<base_include type="dir">boot</base_include>
+			<base_include type="dir">platform</base_include>
+			<base_include type="dir">system</base_include>
+			<base_include type="dir">lib</base_include>
+			<base_include type="dir">sbin</base_include>
+			<base_include type="dir">dev</base_include>
+			<base_include type="dir">devices</base_include>
+			<base_include type="dir">root</base_include>
+			<base_include type="dir">jack</base_include>
+			<base_include type="dir">var/svc/manifest</base_include>
+			<base_include type="dir">var/svc/profile</base_include>
+			<base_include type="dir">var/pkg/catalog</base_include>
+			<base_include type="file">var/pkg/cfg_cache</base_include>
+			<base_include type="dir">etc</base_include>
+			<base_include type="file" fiocompress="false">etc/svc/repository.db</base_include>
+			<base_include type="file" fiocompress="false">etc/dev/.devfsadm_dev.lock</base_include>
+			<base_include type="file" fiocompress="false">etc/name_to_major</base_include>
+			<base_include type="file" fiocompress="false">etc/default/init</base_include>
+		</boot_archive_contents>
+	</img_params>
+	<key_value_pairs/>
+</distribution>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/text_install/text_mode_x86.xml	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,772 @@
+<!--
+    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 2010 Sun Microsystems, Inc.  All rights reserved.
+    Use is subject to license terms.
+
+    XML specification for building the limited language OpenSolaris
+    Text Mode Installer iso and usb image
+-->
+
+<distribution name="OpenSolaris_Text_Installer_X86">
+	<distro_constr_params>
+		<!--
+		     Where to build. This can be a zfs dataset or a mountpoint.
+		     The area will be created if it doesn't exist. If the build_area
+		     is not a zfs dataset or mountpoint, checkpointing will not
+		     be enabled.
+		-->
+		<build_area>rpool/dc</build_area>
+		<distro_constr_flags>
+			<!--
+			     Controls whether the DC should stop
+			     if there is an error when the DC is running 
+			-->
+			<stop_on_error>true</stop_on_error>
+			<!--
+			     You can specify the step to resume the
+			     build from here with the resume_from
+			     attribute field of checkpoint_enable.
+			     This value will be overridden by
+			     the command line if the -r flag is used.
+			     Valid values are step
+			     numbers or name
+			-->
+			<checkpoint_enable>
+				<!--
+				     true implies Checkpointing is enabled
+				-->
+				true
+			</checkpoint_enable>
+		</distro_constr_flags>
+		<output_image>
+			<!--
+			     List of finalizer scripts to be run. They are used
+			     to customize the image and will be run in the
+			     order listed. The name of the checkpoint to
+			     be created when this script is run is required.
+			     The checkpoint message is displayed when the
+			     step is run and is optional.
+			     There are 5 standard arguments that are passed to
+			     every finalizer script (manifest socket, pkg_image path,
+			     tmp dir, boot archive build area, media dir). You may also
+			     specify additional arguments (arg6+) in the argslist.
+			     This argslist is a whitespace-separated list of double
+			     quoted strings.
+			-->
+			<finalizer>
+				<script name="/usr/share/distro_const/im_pop.py">
+					<checkpoint
+						name="im-pop"
+						message="Image area creation"/>
+				</script>
+				<script name="/usr/share/distro_const/pre_boot_archive_pkg_image_mod.py">
+					<checkpoint
+						name="im-mod"
+						message="Image area modifications"/>
+				</script>
+				<script name="/usr/share/distro_const/text_install/tm_pre_boot_archive_pkg_image_mod">
+					<checkpoint
+						name="tm-im-mod"
+						message="Text mode Image area Modifications"/>
+				</script>
+				<script name="/usr/share/distro_const/boot_archive_initialize.py">
+					<checkpoint
+						name="ba-init"
+						message="Boot archive initialization"/>
+				</script>
+				<script name="/usr/share/distro_const/boot_archive_configure">
+					<checkpoint
+						name="ba-config"
+						message="Boot archive configuration"/>
+					<argslist>
+						".textinstall"
+					</argslist>
+				</script>
+				<script name="/usr/share/distro_const/boot_archive_archive.py">
+					<checkpoint
+						name="ba-arch"
+						message="Boot archive archiving (64-bit)"/>
+					<argslist>"amd64"</argslist>
+				</script>
+				<script name="/usr/share/distro_const/boot_archive_archive_32">
+					<checkpoint
+						name="ba-arch-32"
+						message="Boot archive archiving (32-bit)"/>
+					<argslist>"x86"</argslist>
+				</script>
+				<script name="/usr/share/distro_const/post_boot_archive_pkg_image_mod_custom">
+					<checkpoint
+						name="post-mod-custom"
+						message="Post boot archive image area custom modification"/>
+				</script>
+				<script name="/usr/share/distro_const/grub_setup.py">
+					<checkpoint
+						name="grub-setup"
+						message="Grub menu setup"/>
+					<argslist>
+						"text-install"
+					</argslist>
+				</script>
+				<script name="/usr/share/distro_const/post_boot_archive_pkg_image_mod">
+					<checkpoint
+						name="post-mod"
+						message="Post boot archive image area modification"/>
+					<argslist>
+						"usr_zlib_compression=lzma"
+					</argslist>
+				</script>
+				<script name="/usr/share/distro_const/gen_cd_content">
+					<checkpoint
+						name="gen-cd-cont"
+						message="Generate CD image content list"/>
+				</script>
+				<script name="/usr/share/distro_const/create_iso">
+					<checkpoint
+						name="iso"
+						message="ISO image creation"/>
+				</script>
+				<script name="/usr/share/distro_const/create_usb">
+					<checkpoint
+						name="usb"
+						message="USB image creation"/>
+				</script>
+			</finalizer>
+			<boot_archive>
+				<!--
+				     If/how to compress the boot archive. Valid
+				     types are gzip and none
+				-->
+				<compression type="gzip" level="9"/>
+				<!--
+				    SMF service profiles to apply to the 
+				    boot archive. If the "use_build_sys_file" 
+				    attribute is set to true, the build
+				    system's copy of the file is used.  If not 
+				    specified, or "use_build_sys_file" is set 
+				    to false, the image's copy of the file 
+				    is used.
+
+				    Service profiles will be applied to the 
+				    root archive in the order listed.
+				-->
+				<smf_service_profile>
+					<profile path="/var/svc/profile/generic_limited_net.xml"
+					         use_build_sys_file="false"/>
+					<profile path="/usr/share/distro_const/generic_live.xml"
+					         use_build_sys_file="true"/>
+					<profile path="/usr/share/distro_const/text_install/text_live.xml"
+					         use_build_sys_file="true"/>
+					<profile path="/var/svc/profile/ns_files.xml"
+					         use_build_sys_file="false"/>
+				</smf_service_profile>
+			</boot_archive>
+		</output_image>
+	</distro_constr_params>
+	<img_params>
+		<!--
+		     The preferred authority to install packages into the
+		     pkg_image area from.
+		     The default url is: http://pkg.opensolaris.org/release
+		     The default authname is opensolaris.org
+		-->
+		<pkg_repo_default_authority>
+			<main
+				url="http://pkg.opensolaris.org/release"
+				authname="opensolaris.org"/>
+			<!--
+			     If you want to use one or more  mirrors that are
+			     setup for the authority, specify the urls here.
+			-->
+			<!--
+			     Uncomment before using
+			<mirror url="" />
+			-->
+		</pkg_repo_default_authority>
+		<!--
+		     Any additional non-preferred authorities to pull packages
+		     from should be specified here. Multiple additional
+		     authorities may be specified.
+		     If you want to use one or more  mirrors that are
+		     setup for the authority, specify the urls here.
+		-->
+		<!--
+		     Uncomment before using.
+		<pkg_repo_addl_authority>
+			<main
+				url=""
+				authname=""/>
+			<mirror url="" />
+		</pkg_repo_addl_authority>
+		-->
+		<!--
+		     The default preferred authority to be used by the system
+		     after it has been installed.
+		     The default url is: http://pkg.opensolaris.org/release
+		     The default authname is opensolaris.org
+		     If you want to use one or more  mirrors that are
+		     setup for the authority, specify the urls here.
+		-->
+		<post_install_repo_default_authority>
+			<main
+				url="http://pkg.opensolaris.org/release"
+				authname="opensolaris.org"/>
+			<!--
+			     Uncomment before using.
+			<mirror url="" />
+			-->
+		</post_install_repo_default_authority>
+		<!--
+		     Any additional non-preferred authorities to use after the
+		     system has been installed. Multiple additional authorities
+		     may be specified.
+		     If you want to use one or more  mirrors that are
+		     setup for the authority, specify the urls here.
+		-->
+		<!--
+		    Uncomment before using.
+		<post_install_repo_addl_authority>
+			<main
+				url=""
+				authname=""/>
+			<mirror url="" />
+		</post_install_repo_addl_authority>
+		-->
+		<!--
+		     list of packages used to form the installed image
+		-->
+		<packages>
+			<!--
+			     Due to dependency issues, SUNWcsd and SUNWcs
+			     must be listed first in the package list,
+			     and SUNWcsd must precede SUNWcs
+			-->
+			<!--
+			    By default the latest build available, in the
+			    specified IPS repository, is installed.
+			    If another build is required, the build number has
+			    to be appended to the 'entire' package in following
+			    form:
+
+			    <pkg_name="[email protected]#/>
+			-->
+			<pkg name="entire"/>
+			<pkg name="SUNWcsd"/>
+			<pkg name="SUNWcs"/>
+			<pkg name="BRCMbnxe"/>
+			<pkg name="CPQary3"/>
+			<pkg name="SUNW1394"/>
+			<pkg name="SUNWa2ps"/>
+			<pkg name="SUNWacc"/>
+			<pkg name="SUNWaalib"/>
+			<pkg name="SUNWadmap"/>
+			<pkg name="SUNWadmlib-sysid"/>
+			<pkg name="SUNWadmr"/>
+			<pkg name="SUNWad810"/>
+			<pkg name="SUNWadpu320"/>
+			<pkg name="SUNWafe"/>
+			<pkg name="SUNWagp"/>
+			<pkg name="SUNWahci"/>
+			<pkg name="SUNWamd8111s"/>
+			<pkg name="SUNWamr"/>
+			<pkg name="SUNWamt"/>
+			<pkg name="SUNWarcmsr"/>
+			<pkg name="SUNWatge"/>
+			<pkg name="SUNWatfs"/>
+			<pkg name="SUNWauto-install"/>
+			<pkg name="SUNWauto-install-common"/>
+			<pkg name="SUNWbart"/>
+			<pkg name="SUNWbash"/>
+			<pkg name="SUNWbcmsata"/>
+			<pkg name="SUNWbfe"/>
+			<pkg name="SUNWbeadm"/>
+			<pkg name="SUNWbge"/>
+			<pkg name="SUNWbind"/>
+			<pkg name="SUNWbindc"/>
+			<pkg name="SUNWbip"/>
+			<pkg name="SUNWbridge"/>
+			<pkg name="SUNWbtool"/>
+			<pkg name="SUNWbzip"/>
+			<pkg name="SUNWcakr"/>
+			<pkg name="SUNWcar"/>
+			<pkg name="SUNWced"/>
+			<pkg name="SUNWcfcl"/>
+			<pkg name="SUNWcfpl"/>
+			<pkg name="SUNWchxge"/>
+			<pkg name="SUNWckr"/>
+			<pkg name="SUNWcnetr"/>
+			<pkg name="SUNWcpc"/>
+			<pkg name="SUNWcpcu"/>
+			<pkg name="SUNWcpp"/>
+			<pkg name="SUNWcpr"/>
+			<pkg name="SUNWcsl"/>
+			<pkg name="SUNWcups"/>
+			<pkg name="SUNWcups-libs"/>
+			<pkg name="SUNWcurl"/>
+			<pkg name="SUNWdbus"/>
+			<pkg name="SUNWdistro-license-copyright"/>
+			<pkg name="SUNWdialog"/>
+			<pkg name="SUNWdcopy"/>
+			<pkg name="SUNWdmfe"/>
+			<pkg name="SUNWdoc"/>
+			<pkg name="SUNWdrmr"/>
+			<pkg name="SUNWdsd"/>
+			<pkg name="SUNWdtrc"/>
+			<pkg name="SUNWdtrp"/>
+			<pkg name="SUNWemlxs"/>
+			<pkg name="SUNWesu"/>
+			<pkg name="SUNWexpect"/>
+			<pkg name="SUNWfchba"/>
+			<pkg name="SUNWfcip"/>
+			<pkg name="SUNWfcmdb"/>
+			<pkg name="SUNWfcoeu"/>
+			<pkg name="SUNWfcp"/>
+			<pkg name="SUNWfcprt"/>
+			<pkg name="SUNWfcsm"/>
+			<pkg name="SUNWfctl"/>
+			<pkg name="SUNWffilters"/>
+			<pkg name="SUNWfipe"/>
+			<pkg name="SUNWfmd"/>
+			<pkg name="SUNWfppd"/>
+			<pkg name="SUNWfss"/>
+			<pkg name="SUNWftp"/>
+			<pkg name="SUNWfwdc"/>
+			<pkg name="SUNWfwdcu"/>
+			<pkg name="SUNWfwflash"/>
+			<pkg name="SUNWgawk"/>
+			<pkg name="SUNWgcmn"/>
+			<pkg name="SUNWggrp"/>
+			<pkg name="SUNWgnu-coreutils"/>
+			<pkg name="SUNWgnu-diffutils"/>
+			<pkg name="SUNWgnu-findutils"/>
+			<pkg name="SUNWgnu-idn"/>
+			<pkg name="SUNWgnu-mp"/>
+			<pkg name="SUNWgnu-nano"/>
+			<pkg name="SUNWgnu-which"/>
+			<pkg name="SUNWgnutls"/>
+			<pkg name="SUNWgpch"/>
+			<pkg name="SUNWgrub"/>
+			<pkg name="SUNWgsed"/>
+			<pkg name="SUNWgtar"/>
+			<pkg name="SUNWgzip"/>
+			<pkg name="SUNWhal"/>
+			<pkg name="SUNWhmd"/>
+			<pkg name="SUNWhwdata"/>
+			<pkg name="SUNWhxge"/>
+			<pkg name="SUNWib"/>
+			<pkg name="SUNWibsdp"/>
+			<pkg name="SUNWibsdpib"/>
+			<pkg name="SUNWibsdpu"/>
+			<pkg name="SUNWidnl"/>
+			<pkg name="SUNWigb"/>
+			<pkg name="SUNWima"/>
+			<pkg name="SUNWimac"/>
+			<pkg name="SUNWinstall"/>
+			<pkg name="SUNWinstall-l10n"/>
+			<pkg name="SUNWinstall-libs"/>
+			<pkg name="SUNWinstall-test"/>
+			<pkg name="SUNWinstalladm-tools"/>
+			<pkg name="SUNWintgige"/>
+			<pkg name="SUNWipc"/>
+			<pkg name="SUNWipf"/>
+			<pkg name="SUNWipkg"/>
+			<pkg name="SUNWipkg-brand"/>
+			<pkg name="SUNWipmi"/>
+			<pkg name="SUNWipoib"/>
+			<pkg name="SUNWippcore"/>
+			<pkg name="SUNWippl"/>
+			<pkg name="SUNWiscsi"/>
+			<pkg name="SUNWiscsitgt"/>
+			<pkg name="SUNWislcc"/>
+			<pkg name="SUNWiso-codes"/>
+			<pkg name="SUNWixgb"/>
+			<pkg name="SUNWixgbe"/>
+			<pkg name="SUNWkey"/>
+			<pkg name="SUNWkvm"/>
+			<pkg name="SUNWlang-ar"/>
+			<pkg name="SUNWlang-be"/>
+			<pkg name="SUNWlang-bg"/>
+			<pkg name="SUNWlang-ca"/>
+			<pkg name="SUNWlang-common"/>
+			<pkg name="SUNWlang-cs"/>
+			<pkg name="SUNWlang-da"/>
+			<pkg name="SUNWlang-de"/>
+			<pkg name="SUNWlang-deDE"/>
+			<pkg name="SUNWlang-el"/>
+			<pkg name="SUNWlang-en"/>
+			<pkg name="SUNWlang-enUS"/>
+			<pkg name="SUNWlang-es"/>
+			<pkg name="SUNWlang-esES"/>
+			<pkg name="SUNWlang-et"/>
+			<pkg name="SUNWlang-fi"/>
+			<pkg name="SUNWlang-fr"/>
+			<pkg name="SUNWlang-frFR"/>
+			<pkg name="SUNWlang-he"/>
+			<pkg name="SUNWlang-hi"/>
+			<pkg name="SUNWlang-hr"/>
+			<pkg name="SUNWlang-hu"/>
+			<pkg name="SUNWlang-id"/>
+			<pkg name="SUNWlang-is"/>
+			<pkg name="SUNWlang-it"/>
+			<pkg name="SUNWlang-ja"/>
+			<pkg name="SUNWlang-ka"/>
+			<pkg name="SUNWlang-kk"/>
+			<pkg name="SUNWlang-ko"/>
+			<pkg name="SUNWlang-lt"/>
+			<pkg name="SUNWlang-lv"/>
+			<pkg name="SUNWlang-mk"/>
+			<pkg name="SUNWlang-ms"/>
+			<pkg name="SUNWlang-mt"/>
+			<pkg name="SUNWlang-nb"/>
+			<pkg name="SUNWlang-nl"/>
+			<pkg name="SUNWlang-nn"/>
+			<pkg name="SUNWlang-pl"/>
+			<pkg name="SUNWlang-pt"/>
+			<pkg name="SUNWlang-ptBR"/>
+			<pkg name="SUNWlang-ro"/>
+			<pkg name="SUNWlang-ru"/>
+			<pkg name="SUNWlang-sh"/>
+			<pkg name="SUNWlang-sk"/>
+			<pkg name="SUNWlang-sl"/>
+			<pkg name="SUNWlang-sq"/>
+			<pkg name="SUNWlang-sr"/>
+			<pkg name="SUNWlang-sv"/>
+			<pkg name="SUNWlang-th"/>
+			<pkg name="SUNWlang-tr"/>
+			<pkg name="SUNWlang-uk"/>
+			<pkg name="SUNWlang-vi"/>
+			<pkg name="SUNWlang-zhCN"/>
+			<pkg name="SUNWlang-zhHK"/>
+			<pkg name="SUNWlang-zhTW"/>
+			<pkg name="SUNWless"/>
+			<pkg name="SUNWlexpt"/>
+			<pkg name="SUNWlibC"/>
+			<pkg name="SUNWlibdaemon"/>
+			<pkg name="SUNWlibffi"/>
+			<pkg name="SUNWlibgcrypt"/>
+			<pkg name="SUNWlibgpg-error"/>
+			<pkg name="SUNWlibm"/>
+			<pkg name="SUNWlibms"/>
+			<pkg name="SUNWlibpcap"/>
+			<pkg name="SUNWlibpopt"/>
+			<pkg name="SUNWlibsasl"/>
+			<pkg name="SUNWlibsmbclient"/>
+			<pkg name="SUNWlibtasn1"/>
+			<pkg name="SUNWlibusb"/>
+			<pkg name="SUNWlibusbugen"/>
+			<pkg name="SUNWlibvirt"/>
+			<pkg name="SUNWlldap"/>
+			<pkg name="SUNWloc"/>
+			<pkg name="SUNWltdl"/>
+			<pkg name="SUNWlsimega"/>
+			<pkg name="SUNWluxop"/>
+			<pkg name="SUNWlxml"/>
+			<pkg name="SUNWlx"/>
+			<pkg name="SUNWlxsl"/>
+			<pkg name="SUNWman"/>
+			<pkg name="SUNWman-l10n-ja"/>
+			<pkg name="SUNWmd"/>
+			<pkg name="SUNWmdb"/>
+			<pkg name="SUNWmkcd"/>
+			<pkg name="SUNWmpathadm"/>
+			<pkg name="SUNWmpsvplr"/>
+			<pkg name="SUNWmptsas"/>
+			<pkg name="SUNWmrsas"/>
+			<pkg name="SUNWmegasas"/>
+			<pkg name="SUNWmv88sx"/>
+			<pkg name="SUNWmwl"/>
+			<pkg name="SUNWmxfe"/>
+			<pkg name="SUNWmyri10ge"/>
+			<pkg name="SUNWncurses"/>
+			<pkg name="SUNWnet-snmp-core"/>
+			<pkg name="SUNWnet-snmp-utils"/>
+			<pkg name="SUNWnfsc"/>
+			<pkg name="SUNWnfss"/>
+			<pkg name="SUNWnge"/>
+			<pkg name="SUNWnis"/>
+			<pkg name="SUNWntp"/>
+			<pkg name="SUNWntxn"/>
+			<pkg name="SUNWnvsata"/>
+			<pkg name="SUNWnxge"/>
+			<pkg name="SUNWopenssl"/>
+			<pkg name="SUNWos86r"/>
+			<pkg name="SUNWpacket"/>
+			<pkg name="SUNWp7zip"/>
+			<pkg name="SUNWpcelx"/>
+			<pkg name="SUNWpciaccess"/>
+			<pkg name="SUNWpcmci"/>
+			<pkg name="SUNWpcre"/>
+			<pkg name="SUNWpcser"/>
+			<pkg name="SUNWpd"/>
+			<pkg name="SUNWperl-authen-pam"/>
+			<pkg name="SUNWperl-xml-parser"/>
+			<pkg name="SUNWperl584core"/>
+			<pkg name="SUNWperl584man"/>
+			<pkg name="SUNWperl584usr"/>
+			<pkg name="SUNWpicl"/>
+			<pkg name="SUNWpkgcmds"/>
+			<pkg name="SUNWpm"/>
+			<pkg name="SUNWpmcs"/>
+			<pkg name="SUNWpool"/>
+			<pkg name="SUNWpoold"/>
+			<pkg name="SUNWpostgr-83-client"/>
+			<pkg name="SUNWpostgr-83-server"/>
+			<pkg name="SUNWpostgr-83-docs"/>
+			<pkg name="SUNWpowertop"/>
+			<pkg name="SUNWpppd"/>
+			<pkg name="SUNWpppdt"/>
+			<pkg name="SUNWpppg"/>
+			<pkg name="SUNWpr"/>
+			<pkg name="SUNWps"/>
+			<pkg name="SUNWpsdcr"/>
+			<pkg name="SUNWpsdir"/>
+			<pkg name="SUNWpsdpr"/>
+			<pkg name="SUNWpsf"/>
+			<pkg name="SUNWpsm-ipp"/>
+			<pkg name="SUNWpsm-lpd"/>
+			<pkg name="SUNWpython-cherrypy"/>
+			<pkg name="SUNWpython-lxml"/>
+			<pkg name="SUNWpython-mako"/>
+			<pkg name="SUNWpython-ply"/>
+			<pkg name="SUNWpython-pycurl"/>
+			<pkg name="SUNWpython-pyopenssl"/>
+			<pkg name="SUNWpython-twisted"/>
+			<pkg name="SUNWpython-xdg"/>
+			<pkg name="SUNWpython-zope-interface"/>
+			<pkg name="SUNWpyyaml24"/>
+			<pkg name="SUNWqlc"/>
+			<pkg name="SUNWqlcu"/>
+			<pkg name="SUNWrcmdc"/>
+			<pkg name="SUNWrcmds"/>
+			<pkg name="SUNWrge"/>
+			<pkg name="SUNWrmod"/>
+			<pkg name="SUNWrmvolmgr"/>
+			<pkg name="SUNWroute"/>
+			<pkg name="SUNWrpcib"/>
+			<pkg name="SUNWrsync"/>
+			<pkg name="SUNWrtls"/>
+			<pkg name="SUNWrum"/>
+			<pkg name="SUNWsbp2"/>
+			<pkg name="SUNWscsa1394"/>
+			<pkg name="SUNWsdcard"/>
+			<pkg name="SUNWses"/>
+			<pkg name="SUNWsfe"/>
+			<pkg name="SUNWsigcpp"/>
+			<pkg name="SUNWsi3124"/>
+			<pkg name="SUNWslim-utils"/>
+			<pkg name="SUNWsmapi"/>
+			<pkg name="SUNWsmbfs"/>
+			<pkg name="SUNWsmedia"/>
+			<pkg name="SUNWsmpd"/>
+			<pkg name="SUNWsndm"/>
+			<pkg name="SUNWsolnm"/>
+			<pkg name="SUNWsprot"/>
+			<pkg name="SUNWsqlite3"/>
+			<pkg name="SUNWssh"/>
+			<pkg name="SUNWsshcu"/>
+			<pkg name="SUNWsshd"/>
+			<pkg name="SUNWsudo"/>
+			<pkg name="SUNWTcl"/>
+			<pkg name="SUNWTiff"/>
+			<pkg name="SUNWTk"/>
+			<pkg name="SUNWtavor"/>
+			<pkg name="SUNWtcpd"/>
+			<pkg name="SUNWtcsh"/>
+			<pkg name="SUNWtecla"/>
+			<pkg name="SUNWter"/>
+			<pkg name="SUNWtexi"/>
+			<pkg name="system/install/text-install"/>
+			<pkg name="SUNWtftp"/>
+			<pkg name="SUNWtls"/>
+			<pkg name="SUNWtnetc"/>
+			<pkg name="SUNWtnetd"/>
+			<pkg name="SUNWtoo"/>
+			<pkg name="SUNWtop"/>
+			<pkg name="SUNWtpm"/>
+			<pkg name="SUNWts"/>
+			<pkg name="SUNWtss"/>
+			<pkg name="SUNWuacm"/>
+			<pkg name="SUNWudapl"/>
+			<pkg name="SUNWudaplt"/>
+			<pkg name="SUNWudf"/>
+			<pkg name="SUNWuedg"/>
+			<pkg name="SUNWuftdi"/>
+			<pkg name="SUNWugen"/>
+			<pkg name="SUNWuiu8"/>
+			<pkg name="SUNWuksp"/>
+			<pkg name="SUNWukspfw"/>
+			<pkg name="SUNWunzip"/>
+			<pkg name="SUNWuprl"/>
+			<pkg name="SUNWusb"/>
+			<pkg name="SUNWusbs"/>
+			<pkg name="SUNWuwb"/>
+			<pkg name="SUNWvim"/>
+			<pkg name="SUNWvia823x"/>
+			<pkg name="SUNWvr"/>
+			<pkg name="SUNWwbsup"/>
+			<pkg name="SUNWwget"/>
+			<pkg name="SUNWwsr2"/>
+			<pkg name="SUNWxcu4"/>
+			<pkg name="SUNWxge"/>
+			<pkg name="SUNWxvmdom"/>
+			<pkg name="SUNWxvmipa"/>
+			<pkg name="SUNWxvmpv"/>
+			<pkg name="SUNWyge"/>
+			<pkg name="SUNWzfs"/>
+			<pkg name="SUNWzip"/>
+			<pkg name="SUNWzlib"/>
+			<pkg name="SUNWzone"/>
+			<pkg name="SUNWzsh"/>
+			<pkg name="SUNWzyd"/>
+			<pkg name="SUNWDTraceToolkit"/>
+		</packages>
+<!--
+     Items below this line are rarely configured
+-->
+		<!--
+		     If/how to compress the live image.
+		     type = compression algorithm to use for pkg.zlib and misc.zlib.
+		     Valid types are lzma, gzip, and none.
+		-->
+		<live_img_compression type="lzma"/>
+		<!--
+		     Grub menu modifications. Will use menu.lst if not specified
+		-->
+		<grub_menu_modifications>
+			<!--
+			    Specify a title for the grub menu.
+			    If a title for the grub menu is not specified,
+			    the first line of /etc/release will be used as
+			    the title for the grub menu
+			-->
+			<!--
+			     Uncomment before using
+			<title>Special Grub Title Text</title>
+			-->
+			<timeout>5</timeout>
+
+		</grub_menu_modifications>
+		<!--
+		     Indicate whether the IPS index should be generated for
+		     pkg install and uninstall.  The default is to not
+		     generate the IPS search index
+		-->
+		<generate_ips_search_index>
+			false
+		</generate_ips_search_index>
+		<!--
+		     Files and dirs to be included in the boot archive of all media
+		     delivered by this distribution. Boot archive contains the
+		     minimal list of contents in order to be able to
+		     boot and setup a running system. These files and dirs
+		     must exist in the pkg_image area.
+		-->
+		<boot_archive_contents>
+			<base_include type="file">usr/sbin/pmadm</base_include>
+			<base_include type="file">usr/sbin/lofiadm</base_include>
+			<base_include type="file">usr/sbin/devfsadm</base_include>
+			<base_include type="file">usr/sbin/modload</base_include>
+			<base_include type="file">usr/sbin/i86/modload</base_include>
+			<base_include type="file">usr/sbin/mount</base_include>
+			<base_include type="file">usr/sbin/hostconfig</base_include>
+			<base_include type="file">usr/sbin/chroot</base_include>
+			<base_include type="file">usr/sbin/syslogd</base_include>
+			<base_include type="file">usr/bin/coreadm</base_include>
+			<base_include type="file">usr/bin/bash</base_include>
+			<base_include type="file">usr/bin/ksh</base_include>
+			<base_include type="file">usr/bin/cat</base_include>
+			<base_include type="file">usr/bin/echo</base_include>
+			<base_include type="file">usr/bin/false</base_include>
+			<base_include type="file">usr/bin/grep</base_include>
+			<base_include type="file">usr/bin/ls</base_include>
+			<base_include type="file">usr/bin/rm</base_include>
+			<base_include type="file">usr/bin/svcprop</base_include>
+			<base_include type="file">usr/bin/true</base_include>
+			<base_include type="file">usr/bin/cd</base_include>
+			<base_include type="file">usr/bin/test</base_include>
+			<base_include type="file">usr/bin/sleep</base_include>
+			<base_include type="file">usr/bin/expr</base_include>
+			<base_include type="file">usr/bin/vi</base_include>
+			<base_include type="file">usr/has/bin/vi</base_include>
+			<base_include type="file">usr/lib/fs/hsfs/fstyp</base_include>
+			<base_include type="file">usr/lib/fs/hsfs/fstyp.so.1</base_include>
+			<base_include type="file">usr/lib/fs/hsfs/mount</base_include>
+			<base_include type="file">usr/lib/fs/ufs/fstyp</base_include>
+			<base_include type="file">usr/lib/fs/ufs/fstyp.so.1</base_include>
+			<base_include type="file">usr/lib/fs/ufs/mount</base_include>
+			<base_include type="file">usr/lib/libfstyp.so.1</base_include>
+			<base_include type="file">usr/lib/platexec</base_include>
+			<base_include type="file">usr/lib/devfsadm/devfsadmd</base_include>
+			<base_include type="file">usr/lib/libm.so.2</base_include>
+			<base_include type="file">usr/lib/libm.so</base_include>
+			<base_include type="file">usr/lib/libfstyp.so</base_include>
+			<base_include type="file">usr/lib/libz.so</base_include>
+			<base_include type="file">usr/lib/libz.so.1</base_include>
+			<base_include type="file">usr/bin/i86/ksh93</base_include>
+			<base_include type="file">usr/lib/isaexec</base_include>
+			<base_include type="file">usr/lib/libast.so.1</base_include>
+			<base_include type="file">usr/lib/libcmd.so.1</base_include>
+			<base_include type="file">usr/lib/libdll.so.1</base_include>
+			<base_include type="file">usr/lib/libshell.so.1</base_include>
+			<base_include type="file">usr/share/lib/xml/dtd/service_bundle.dtd.1</base_include>
+			<base_include type="file">var/sadm/install/admin/default</base_include>
+			<base_include type="file">var/sadm/system/admin/default_java</base_include>
+			<base_include type="file">var/sadm/install/contents</base_include>
+			<base_include type="file">var/adm/utmpx</base_include>
+			<base_include type="file">var/adm/wtmpx</base_include>
+			<base_include type="file">var/adm/aculog</base_include>
+			<base_include type="file">var/lib/postrun/postrun-runq</base_include>
+			<base_include type="file">var/lib/postrun/postrun</base_include>
+			<base_include type="file">var/log/postrun.log</base_include>
+			<base_include type="file">var/log/authlog</base_include>
+			<base_include type="file">var/log/syslog</base_include>
+			<base_include type="file">var/saf/zsmon/log</base_include>
+			<base_include type="file">var/spool/cron/crontabs/adm</base_include>
+			<base_include type="file">var/spool/cron/crontabs/root</base_include>
+			<base_include type="file">var/nis/NIS+LDAPmapping.template</base_include>
+			<base_include type="file">var/yp/aliases</base_include>
+			<base_include type="file">var/yp/nicknames</base_include>
+			<base_include type="dir">kernel</base_include>
+			<base_include type="dir">boot</base_include>
+			<base_include type="dir">platform</base_include>
+			<base_include type="dir">system</base_include>
+			<base_include type="dir">lib</base_include>
+			<base_include type="dir">sbin</base_include>
+			<base_include type="dir">dev</base_include>
+			<base_include type="dir">devices</base_include>
+			<base_include type="dir">usr/lib/devfsadm/linkmod</base_include>
+			<base_include type="dir">root</base_include>
+			<base_include type="dir">jack</base_include>
+			<base_include type="dir">var/svc/manifest</base_include>
+			<base_include type="dir">var/svc/profile</base_include>
+			<base_include type="dir">var/pkg/catalog</base_include>
+			<base_include type="file">var/pkg/cfg_cache</base_include>
+			<base_include type="dir">etc</base_include>
+			<base_exclude type="dir">etc/gconf</base_exclude>
+			<base_exclude type="dir">etc/brltty</base_exclude>
+			<base_exclude type="dir">etc/gtk-2.0</base_exclude>
+			<base_exclude type="dir">etc/notices</base_exclude>
+		</boot_archive_contents>
+	</img_params>
+	<key_value_pairs>
+		<pair key="iso_sort"
+		    value="/usr/share/distro_const/text_install/text_install_x86_iso.sort"/>
+	</key_value_pairs>
+</distribution>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/text_install/tm_pre_boot_archive_pkg_image_mod	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,100 @@
+#!/bin/ksh
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+# =============================================================================
+# =============================================================================
+# tm_pre_boot_archive_pkg_image_mod
+#
+# pkg_image area modifications specific for text installer, to be made before
+# the boot archive is built (possibly to prepare the pkg_image area for boot
+# archive build)
+# =============================================================================
+# =============================================================================
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Main
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Perform pkg_image area modifications specific for text install before the
+# boot archive is built.  This finalizer script is to be called before the
+# boot archive build is complete.
+# 
+# Args:
+#   MFEST_SOCKET: Socket needed to get manifest data via ManifestRead object
+#	(not used)
+#
+#   PKG_IMG_PATH: Package image area
+#
+#   TMP_DIR: Temporary directory (not used)
+#
+#   BA_BUILD: Area where boot archive is put together (not used)
+#
+#   MEDIA_DIR: Area where the media is put (not used)
+#
+# Of these automatically-passed variables, only the PKG_IMG_PATH is actually
+# used.
+#
+# Note: This assumes pkg_image area is intact.
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+if [ "$#" != "5" ] ; then
+	print -u2 "Usage: $0: Requires 5 args:"
+	print -u2 "    Reader socket, pkg_image area, tmp dir,"
+	print -u2 "    boot archive build area, media area"
+	exit 1
+fi
+
+PKG_IMG_PATH=$2
+if [ ! -d $PKG_IMG_PATH ] ; then
+	print -u2 "$0: Image package area $PKG_IMG_PATH is not valid"
+	exit 1
+fi
+
+# Define a few commands
+CAT=/usr/bin/cat
+CD=cd			# Built into the shell
+CHROOT=/usr/sbin/chroot
+CPIO=/usr/bin/cpio
+RM=/usr/bin/rm
+SH=/usr/bin/sh
+MKDIR=/usr/bin/mkdir
+CP=/usr/bin/cp
+SED=/usr/bin/sed
+TOUCH=/usr/bin/touch
+
+# Path under which to save original files for restoration by ICT module
+SAVE_PATH=${PKG_IMG_PATH}/save
+
+# Modify /etc/system to make ZFS less mem hungry
+$MKDIR -p ${SAVE_PATH}/etc
+$CP -p ${PKG_IMG_PATH}/etc/system ${SAVE_PATH}/etc
+$CAT <<EOF >>${PKG_IMG_PATH}/etc/system
+set zfs:zfs_arc_max=0x4002000
+set zfs:zfs_vdev_cache_size=0
+EOF
+
+exit 0
--- a/usr/src/cmd/distro_const/utils/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/distro_const/utils/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -34,17 +34,20 @@
 PYMODULES=	boot_archive_initialize.py \
 		boot_archive_archive.py \
 		grub_setup.py \
-		pre_boot_archive_pkg_image_mod.py \
-		im_pop.py
+		im_pop.py \
+		plat_setup.py \
+		pre_boot_archive_pkg_image_mod.py
 
 PYCMODULES=	$(PYMODULES:%.py=%.pyc)
 
 DC_UTIL_FILES=	mkrepo \
 		create_iso \
 		create_usb \
+		gen_cd_content \
 		boot_archive_configure \
 		boot_archive_strip \
 		post_boot_archive_pkg_image_mod \
+		post_boot_archive_pkg_image_mod_custom \
 		generic_live.xml \
 		$(PYMODULES)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/utils/gen_cd_content	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,107 @@
+#!/bin/ksh
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Main
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# gen_cd_content
+#
+# Generate the list of files that are part of the (LiveCD/Text Install) 
+# media image. The result will be stored in the file .livecd-cdrom-content 
+# in the root of the image.
+#
+# The content of the .livecd-cdrom-content file will be used by the
+# Transfer Module to determine what files are part of the media image.
+# The transfer module will ignore all other files on the media that
+# are not in the .livecd-cdrom-content file
+#
+# This finalizer script must be placed immediately before the finalizer
+# script to create the ISO file for the (LiveCD/Text Install) media, 
+# otherwise, content of the cd might get modified further, and the 
+# content list might not be accurate.
+#
+# The following files will NOT be included in the .livecd-cdrom-content file
+#
+# 1) *.zlib
+# 2) .livecd-cdrom-content
+# 3) .image_info
+# 
+# ==========================================================================
+# Args:
+#   MFEST_SOCKET: Socket needed to get manifest data via ManifestRead object
+#	(not used)
+#
+#   PKG_IMG_PATH: Package image area
+#
+#   TMP_DIR: Temporary directory to contain the boot archive file (not used)
+#
+#   BA_BUILD: Area where boot archive is put together (not used)
+#
+#   MEDIA_DIR: Area where the media is put (not used)
+#
+# Of these automatically-passed variables, only the PKG_IMG_PATH is actually
+# used.
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+if [ "$#" != "5" ] ; then
+	print -u2 "Usage: $0: Requires 5 args:"
+	print -u2 "    Reader socket, pkg_image area, tmp dir,"
+	print -u2 "    boot archive build area, media area"
+	exit 1
+fi
+
+PKG_IMG_PATH=$2
+if [ ! -d ${PKG_IMG_PATH} ] ; then
+	print -u2 "$0: Image package area $PKG_IMG_PATH is not valid"
+	exit 1
+fi
+
+FIND=/usr/bin/find
+CD=cd	#use the "cd" built-in to the shell
+
+IMG_CONTENT_FILE=".livecd-cdrom-content"
+IMG_INFO_FILE=".image_info"
+BOOT_ARCHIVE_BASE="boot_archive"
+
+#
+# The package image area is the "root" of the live CD
+#
+${CD} ${PKG_IMG_PATH}
+if [ "$?" != "0" ] ; then
+	print -u2 "$0: unable to change into ${PKG_IMG_PATH}."
+	exit 1
+fi
+
+${FIND} . ! \( -name '*.zlib' -o -name ${IMG_INFO_FILE} \
+	-o -name ${IMG_CONTENT_FILE} -o -name ${BOOT_ARCHIVE_BASE} \) -print \
+	> ${IMG_CONTENT_FILE}
+
+if [ "$?" != "0" ] ; then
+	print -u2 "$0:  there's an error generating the image content list."
+	exit 1
+fi
+
+exit 0
--- a/usr/src/cmd/distro_const/utils/grub_setup.py	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/distro_const/utils/grub_setup.py	Tue Mar 16 14:07:17 2010 -0700
@@ -227,12 +227,6 @@
     ENTRY.append("\tkernel$ /platform/i86pc/kernel/$ISADIR/unix -B install=true,console=ttyb")
     ENTRY.append("\tmodule$ /platform/i86pc/$ISADIR/boot_archive")
     ENTRIES.append(ENTRY)
-
-    ENTRY = []
-    ENTRY.append("title Boot from Hard Disk")
-    ENTRY.append("\trootnoverify (hd0)")
-    ENTRY.append("\tchainloader +1")
-    ENTRIES.append(ENTRY)
 elif (GRUB_SETUP_TYPE == "livecd"):
     # The following entries are the standard "hardwired" entries for livecd.
     MENU_LST_FILE.write("splashimage=/boot/grub/splash.xpm.gz\n")
@@ -256,13 +250,26 @@
     ENTRY.append("\tkernel$ /platform/i86pc/kernel/$ISADIR/unix -B livemode=text")
     ENTRY.append("\tmodule$ /platform/i86pc/$ISADIR/boot_archive")
     ENTRIES.append(ENTRY)
+elif (GRUB_SETUP_TYPE == "text-install"):
+    # The following entries are the standard "hardwired" entries for 
+    # the text-installer
+    # The menu.lst is hidden by default. GRUB doesn't show the menu.lst
+    # on the control terminal and automatically boots the default entry, 
+    # unless interrupted by pressing <ESC> before the timeout expires.
+    MENU_LST_FILE.write("hiddenmenu\n")
 
     ENTRY = []
-    ENTRY.append("title Boot from Hard Disk")
-    ENTRY.append("\trootnoverify (hd0)")
-    ENTRY.append("\tchainloader +1")
+    ENTRY.append("title " + RELEASE)
+    ENTRY.append("\tkernel$ /platform/i86pc/kernel/$ISADIR/unix")
+    ENTRY.append("\tmodule$ /platform/i86pc/$ISADIR/boot_archive")
     ENTRIES.append(ENTRY)
 
+ENTRY = []
+ENTRY.append("title Boot from Hard Disk")
+ENTRY.append("\trootnoverify (hd0)")
+ENTRY.append("\tchainloader +1")
+ENTRIES.append(ENTRY)
+
 # This all assumes that data is returned from the manifest in the order it is
 # provided.  Otherwise, lines within an entry could be out of order.
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/utils/plat_setup.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,81 @@
+#!/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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+""" plat_setup
+
+ Platform specific customizations for sparc
+
+ To be done before post_boot_archive_pkg_image_mod gets called.
+
+"""
+
+import os
+import sys
+from osol_install.distro_const.dc_defs import BA_FILENAME_SUN4U
+from osol_install.distro_const.dc_defs import BA_FILENAME_SUN4V
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Main
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+""" Platform specific customizations for sparc.
+
+Args:
+  MFEST_SOCKET: Socket needed to get manifest data via ManifestRead object
+
+  PKG_IMG_PATH: Package image area mountpoint
+
+  TMP_DIR: Temporary directory (not used)
+
+  BA_BUILD: Area where boot archive is put together.  (not used)
+
+  MEDIA_DIR: Area where the media is put. (not used)
+
+  KERNEL_ARCH: Machine type for archive
+
+Note: This assumes a populated pkg_image area exists at the location
+	${PKG_IMG_PATH}
+
+"""
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+if (len(sys.argv) != 6): # Don't forget sys.argv[0] is the script itself.
+    raise Exception, (sys.argv[0] + ": Requires 5 args:\n" +
+                                    "    Reader socket, pkg_image area, " +
+                                    "temp dir,\n" +
+                                    "    boot archive build area, " +
+                                    "media area.")
+
+# collect input arguments from what this script sees as a commandline.
+PKG_IMG_PATH = sys.argv[2]	# package image area mountpoint
+
+# Create the symlink from sun4v/boot_archive to sun4u/boot_archive
+# The sun4u/boot_archive is the real boot_archive. We're using
+# the same boot_archive for sun4v as sun4u.
+try:
+    os.symlink("../.." + BA_FILENAME_SUN4U,
+               PKG_IMG_PATH + BA_FILENAME_SUN4V)
+except OSError, (errno, strerror):
+    print >> sys.stderr, "Error creating symlink for sun4v boot_archive"
+    raise
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/utils/post_boot_archive_pkg_image_mod_custom	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,100 @@
+#!/bin/ksh
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+# =============================================================================
+# =============================================================================
+# post_boot_archive_pkg_image_mod_custom
+#
+# Customizations to the package image area after boot archive 
+# construction completes
+# =============================================================================
+# =============================================================================
+
+
+# Define a few commands.
+RM=/usr/bin/rm
+MV=/usr/bin/mv
+CP=/usr/bin/cp
+LN=/usr/bin/ln
+FIND=/usr/bin/find
+XARGS=/usr/bin/xargs
+UNAME=/usr/bin/uname
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Main
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Customizations to the package image area after boot archive construction
+# completes.
+# 
+# Args:
+#   MFEST_SOCKET: Socket needed to get manifest data via ManifestRead
+#		object (not used)
+#
+#   PKG_IMG_PATH: Package image area
+#
+#   TMP_DIR: Temporary directory to contain the boot archive file (not used)
+#
+#   BA_BUILD: Area where boot archive is put together (not used)
+#
+#   MEDIA_DIR: Area where the media is put. (Not used)
+# 
+# Note: This assumes a populated pkg_image area exists at the location
+#		${PKG_IMG_PATH} and that the boot archive has been built.
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+if [ "$#" != "5" ] ; then
+	print -u2 "Usage: $0: Requires 5 args:"
+	print -u2 "    Reader socket, pkg_image area, tmp_dir,"
+	print -u2 "    boot archive build area, media area"
+	exit 1
+fi
+
+PKG_IMG_PATH=$2
+if [ ! -d $PKG_IMG_PATH ] ; then
+	print -u2 "$0: Image package area $PKG_IMG_PATH is not valid"
+	exit 1
+fi
+
+# Platform only needs to contain the kernel and boot_archive for x86 and
+# in the case of a sparc image, wanboot and the boot_archive.
+initial_cwd=`pwd`
+if [ -d ${PKG_IMG_PATH}/platform ] ; then
+    cd ${PKG_IMG_PATH}/platform
+    if [ `$UNAME -p` == "sparc" ] ; then
+	$FIND . -type f -a ! -name wanboot -a ! -name boot_archive | \
+	    $XARGS $RM -f
+        cd ${PKG_IMG_PATH}
+	${LN} -s ../platform boot/platform
+    else
+        $FIND . -type f -a ! -name unix -a ! -name boot_archive | $XARGS $RM -f
+        # GRUB does not understand symlinks, so make copies
+        cd ${PKG_IMG_PATH}
+        ${CP} -r ${PKG_IMG_PATH}/platform ${PKG_IMG_PATH}/boot
+    fi
+fi
+cd ${initial_cwd}
+
+exit 0
--- a/usr/src/cmd/slim-install/config/set_lang	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/slim-install/config/set_lang	Tue Mar 16 14:07:17 2010 -0700
@@ -121,7 +121,7 @@
 
 # remove entries which are not supported
 for (( j=0, i=0 ; i < languages.list_len ; i++ )) ; do
-        nameref node=languages.fixedlist[i]
+        nameref node=languages.fixedlist[$i]
 
 	# check whether we have a module for this locale ("C" and "POSIX"
 	# are always supported)
@@ -176,7 +176,7 @@
 
 	# Prompt user to select language and check for valid entry
 	while true ; do
-		readintval choice $"To select desktop language, enter a number [default is ${languages.default}]: " || continue
+		readintval choice $"To select the language you wish to use, enter a number [default is ${languages.default}]: " || continue
 
 		# check for valid option
 		(( choice >= 1 && choice <= languages.list_len )) && break
--- a/usr/src/cmd/slim-install/finish/install-finish	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/slim-install/finish/install-finish	Tue Mar 16 14:07:17 2010 -0700
@@ -64,6 +64,17 @@
     else:
         return 0
 
+# Test to see if running in a text install environment
+def textinstall_exists():
+    '''
+    textinstall_exists - Determine if this script is being
+    invoked from a Text Install.
+    '''
+    if os.path.exists('/.textinstall'):
+        return 1
+    else:
+        return 0
+
 # Test to see if running on a SPARC platform
 IS_SPARC = (platform.platform().find('sparc') >= 0)
 
@@ -77,10 +88,11 @@
 NU_PW = ""             # argument p
 NU_GID = "101"         # argument G
 NU_UID = "10"          # argument U
+NO_NETWORK = False     # argument N
 
 #parse command line arguments
 try:
-    OPTS, ARGS = getopt.getopt(sys.argv[1:],'B:d:R:n:l:p:G:U:')
+    OPTS, ARGS = getopt.getopt(sys.argv[1:],'B:d:R:n:l:p:G:U:N')
 
 except getopt.GetoptError, err:
     prerror('Parsing command line arguments failed. (%s)' % str(err))
@@ -94,6 +106,8 @@
     prerror('       [-p <new user password>] - default is blank')
     prerror('       [-G <new user GID>] - default is 101')
     prerror('       [-U <new user UID>] - default is 10')
+    prerror('       [-N] - do not configure networking.  ' + \
+            'Default is configure nwam.  Only applicable to text install')
     sys.exit(ICT_INVALID_PARAMETER)
 
 for o, a in OPTS:
@@ -113,6 +127,8 @@
         NU_GID = a
     if o in '-U':
         NU_UID = a
+    if o in '-N':
+        NO_NETWORK = True
 
 #perform ICT initialization, specifying root target path, debugging level
 
@@ -209,9 +225,10 @@
         SA.append(ICTO.update_boot_archive())
 
 else:
-    # Doing a GUI install
+    # Doing a GUI install or a Text Install
 
     # At this time there is no SPARC specific processed needed for GUI install
+    # SPARC specific processing is needed for Text Install
 
     #ICTs ported from Transfer Module
     SA.append(ICTO.create_smf_repository())
@@ -220,30 +237,48 @@
     SA.append(ICTO.keyboard_layout())
     SA.append(ICTO.delete_misc_trees())
     #ICTs ported from original install-finish
-    SA.append(ICTO.set_prop_from_eeprom('keyboard-layout'))
-    SA.append(ICTO.set_boot_device_property())
-    SA.append(ICTO.add_splash_image_to_grub_menu())
+    if not IS_SPARC:
+        SA.append(ICTO.set_prop_from_eeprom('keyboard-layout'))
+        SA.append(ICTO.set_boot_device_property())
+        SA.append(ICTO.add_splash_image_to_grub_menu())
     SA.append(ICTO.fix_browser_home_page())
     SA.append(ICTO.remove_livecd_coreadm_conf())
     SA.append(ICTO.set_partition_active())
-    SA.append(ICTO.remove_bootpath())
-    SA.append(ICTO.fix_grub_entry())
-    SA.append(ICTO.add_operating_system_grub_entry())
+    if not IS_SPARC:
+        SA.append(ICTO.remove_bootpath())
+        SA.append(ICTO.fix_grub_entry())
+        SA.append(ICTO.add_operating_system_grub_entry())
     SA.append(ICTO.update_dumpadm_nodename())
-    SA.append(ICTO.explicit_bootfs())
-    SA.append(ICTO.enable_happy_face_boot())
-    SA.append(ICTO.copy_splash_xpm())
+    if IS_SPARC:
+        SA.append(ICTO.create_sparc_boot_menu())
+        SA.append(ICTO.copy_sparc_bootlst())
+    else:
+        SA.append(ICTO.explicit_bootfs())
+        if not textinstall_exists():
+            SA.append(ICTO.enable_happy_face_boot())
+    SA.append(ICTO.update_boot_archive())
+    if not IS_SPARC:
+        SA.append(ICTO.copy_splash_xpm())
     SA.append(ICTO.smf_correct_sys_profile())
     SA.append(ICTO.add_sysidtool_sys_unconfig())
-    SA.append(ICTO.enable_nwam())
+    if textinstall_exists():
+        pkg_remove_list = ['SUNWslim-utils', 'system/install/text-install']
+    else:
+        # GUI installer
+        pkg_remove_list = ['SUNWslim-utils', 'SUNWgui-install']
+    if NO_NETWORK:
+        SA.append(ICTO.do_not_configure_network())
+    else:
+        SA.append(ICTO.enable_nwam())
+
     SA.append(ICTO.remove_livecd_environment())
-    SA.append(ICTO.remove_specific_packages(['SUNWslim-utils',
-                                             'SUNWgui-install']))
+    SA.append(ICTO.remove_specific_packages(pkg_remove_list))
     SA.append(ICTO.set_flush_content_cache_false())
     SA.append(ICTO.set_root_password(ROOT_PW))
     SA.append(ICTO.create_new_user(NU_GOS, NU_LOGIN, NU_PW, NU_GID, NU_UID))
     SA.append(ICTO.set_homedir_map(NU_LOGIN))
-    SA.append(ICTO.copy_capability_file())
+    if not IS_SPARC:
+        SA.append(ICTO.copy_capability_file())
     SA.append(ICTO.reset_image_uuid())
     SA.append(ICTO.update_boot_archive())
 
--- a/usr/src/cmd/slim-install/svc/media-fs-root	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/cmd/slim-install/svc/media-fs-root	Tue Mar 16 14:07:17 2010 -0700
@@ -31,11 +31,16 @@
 # Make sure that the libraries essential to this stage of booting can be found.
 LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH
 
-# Set flags to indicate whether we are in LiveCD or AI environment
+#
+# Set flags to indicate whether we are in LiveCD, AI or text installer
+# environment
+#
 LIVECD=0
 AUTOINSTALL=0
+TEXTINSTALL=0
 [ -f /.livecd ] && LIVECD=1
 [ -f /.autoinstall ] && AUTOINSTALL=1
+[ -f /.textinstall ] && TEXTINSTALL=1
 
 PRTCONF=/usr/sbin/prtconf
 SED=/usr/bin/sed
@@ -57,6 +62,8 @@
 	echo "\rPreparing live image for use" >/dev/msglog
 elif [ $AUTOINSTALL = 1 ]; then
 	echo "\rPreparing automated install image for use" >/dev/msglog
+elif [ $TEXTINSTALL = 1 ]; then
+	echo "\rPreparing text install image for use" >/dev/msglog
 fi
 
 # Determine if any of the USB devices contains a UFS filesystem.
@@ -131,6 +138,8 @@
 	echo "Done mounting Live image" > /dev/msglog
 elif [ $AUTOINSTALL = 1 ]; then
 	echo "Done mounting automated install image" > /dev/msglog
+elif [ $TEXTINSTALL = 1 ]; then
+	echo "Done mounting text install image" > /dev/msglog
 fi
 
 #
@@ -272,6 +281,12 @@
 		/usr/sbin/svcadm enable application/graphical-login/gdm
 	fi
 
+elif [ $TEXTINSTALL = 1 ]
+then
+	# Get keyboard layout from user.
+	exec </dev/console >/dev/console 2>&1
+	/usr/bin/kbd -s
+	/usr/sbin/set_lang
 fi
 
 exit $SMF_EXIT_OK
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,51 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.cmd
+
+all:=		TARGET= all
+clean:=		TARGET= clean
+clobber:=	TARGET= clobber
+install:=	TARGET= install
+
+SUBDIRS=	osol_install/text_install osol_install/profile svc helpfiles
+
+.KEEP_STATE:
+
+all:	$(SUBDIRS)
+
+clean:	$(SUBDIRS)
+
+clobber: clean
+
+install: all $(SUBDIRS)
+
+$(SUBDIRS): FRC
+	cd $@; pwd; echo $(TARGET); $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,63 @@
+
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../../Makefile.cmd
+
+all:=		TARGET=	all
+clean:=		TARGET=	clean
+clobber:=	TARGET=	clobber
+install:=	TARGET=	install
+
+HELP_FILES=	date_time.txt \
+		disks.txt \
+		network_manual.txt \
+		network.txt \
+		sparc_solaris_slices_select.txt \
+		sparc_solaris_slices.txt \
+		summary.txt \
+		timezone.txt \
+		users.txt \
+		welcome.txt \
+		x86_fdisk_partitions_select.txt \
+		x86_fdisk_partitions.txt \
+		x86_fdisk_slices_select.txt \
+		x86_fdisk_slices.txt
+
+ROOTHELP_FILES=	$(HELP_FILES:%=$(ROOTUSRSHARETI)/%)
+
+$(ROOTUSRSHARETI):
+	$(INS.dir)
+
+all: $(ROOTUSRSHARETI)
+
+clean:	
+	rm -rf $(ROOTUSRSHARETI)
+
+clobber: clean
+
+install: all .WAIT $(ROOTHELP_FILES)
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/date_time.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,19 @@
+DATE AND TIME
+
+This screen enables you to set or reset the computer's internal clock. 
+
+If possible, the initial settings in this screen will be the computer's current internal clock settings.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the installer screen, you can accept the initial settings in this screen by pressing F2. Or you can use the arrow keys to move to each editable field and type new settings. Then press F2 to continue with the new settings. 
+
+Note: If you type an invalid entry, an error message displays on the screen.
+
+If you change to a month that has fewer days than the current Day setting, the Day setting is automatically changed to the last day of the new month. 
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/disks.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,46 @@
+DISKS
+
+This screen displays the internal disks and external storage devices that can be used as installation targets. To be recognized by the installer, the devices must be plugged in when the installer begins. 
+
+Note: You do not need to set up a mirrored configuration during installation. You can use the ZFS attach command after installation to perform this task. If you plan to set up a mirrored configuration, remember that the second disk has to be equal or larger than the installation target. 
+
+WARNING: Note the following important considerations for x86 installations:
+
+	* If the disk was not previously partitioned, the installation, by default, overwrites the whole disk layout. You can, however, modify the default selections in the installer screens to install to a new Solaris partition that is smaller than the whole disk.
+
+	* If a Solaris partition is on the disk, and the installation makes no modifications to the partitions, the installation overwrites the Solaris partition only. Other existing partitions are not changed. 
+
+Note: No actual changes will be made to the system until you complete the installer selection screens and begin the actual installation process.
+
+SIZE
+
+The recommended size and minimum size for the OpenSolaris OS installation are displayed. The size of each device is displayed in gigabytes. 
+
+* Devices that are too small for a successful installation are labeled that way. 
+
+* Some devices may be so large that an OpenSolaris installation cannot use all the space on the device. These devices have a maximum installation size specified.
+
+PARTITIONS OR SLICES
+
+The first section of the screen lists available devices. One device is highlighted by default. The next section of the screen displays the partition or slice information for the currently highlighted device. Partitions are listed for x86 formatted devices. Slices are listed for SPARC formatted devices.
+
+If you want to view the partition or slice information for another device, you can use the arrow keys to select that device. The screen changes to display the partition or slice information for the device that you select.
+
+If there are more than four devices, press the up/down arrow keys repeatedly to scroll down to the other devices. 
+
+CAUTION: If there are no existing partitions or slices for a device, the screen displays proposed partition or slice setup. In this case, all existing data on the device would be destroyed during installation.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the installer screen, choose one of the following options:
+
+     * If you want to install to the device that is currently highlighted, select F2 and the installation continues to the next screen.
+
+     * If you want to select a different device for the installation, use the arrow keys to highlight your preferred device. Partition or slice information will display for the device that you select. Then press F2 to continue. 
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/network.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,26 @@
+NETWORK 
+
+This screen prompts you to type a computer host name and to specify how the network connection should be configured.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the installer screen, enter network information as follows:
+
+* COMPUTER NAME - This screen includes an editable field for the computer name. The editable field is highlighted. With the computer host name field selected, type a name for this computer that identifies it on the network. Note the following restrictions:
+
+     * The host name must be at least two characters. 
+     * The host name can contain letters, numbers, and minus signs (-).
+
+* NETWORK CONNECTION - Use the arrow keys to select a network connection choice from the following options:                  
+
+     Automatically - Use DHCP to configure the connection.
+     Manually      - If you select this option, you will select and configure a wired network interface on the following screens. 
+     None          - Do not configure the network during the installation.
+ 
+Press F2 to continue to the next screen. 
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/network_manual.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,34 @@
+MANUAL NETWORK CONFIGURATION
+
+The manual network screen or screens enable you to manually set the machine's network settings. First, if there is more than one interface, you select a connection to be configured. Then, you type the settings for the connection. 
+
+Note: Only one connection can be configured during the installation.
+
+GUIDELINES
+
+These screens include editable fields that are highlighted when the field is selected. Use the arrow keys to select each field. When a field is selected, you can type your settings in that field.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, complete the manual configuration information as follows:
+
+1. If there is more than one interface, in the first screen, use the arrow keys to highlight the connection that you want to configure. Then, press F2 to continue to the next screen.
+
+2. Use the arrow keys to move to each configuration field for the connection that you want to configure.
+
+Note: For fields where the configuration information was automatically detected by the installer, the configuration information is displayed. 
+
+3. For each configuration field, you can type connection settings or accept the default values. Follow the restrictions for each field as specified in the screen. Type the settings or accept the default values for the following fields:
+	* IP Address - required field
+	* Netmask - required field
+	* Gateway - optional field
+	* DNS - optional field
+	* Domain - optional field
+
+Then press F2 to continue to the next screen with the network settings that you have specified. 
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/sparc_solaris_slices.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,22 @@
+SPARC: SOLARIS SLICES
+
+This screen displays the VTOC slices for the SPARC storage device that you selected in the previous screen. The slices are listed in layout order. 
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the installer screen, use the arrow keys to highlight either "Use the whole disk" or "Use a slice on the disk." 
+
+     * If you select "Use a slice on the disk," the next screen enables you to select which slice to use for the installation and to make changes to the slice layout.
+
+     * If you select "Use the whole disk," the installer records that choice and proceeds to the next task.
+
+       CAUTION: The "Use the whole disk" selection erases the entire disk during installation. The disk is overwritten with the new OpenSolaris OS. 
+
+Press F2 to continue to the next screen.
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/sparc_solaris_slices_select.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,49 @@
+SPARC: SELECT SLICE
+
+This screen enables you to select a VTOC slice to use for the installation. To indicate which slice to use for the installation, select the slice and change its type to rpool. You also have the option of resizing the rpool.
+
+The screen displays the existing slices in the device that you selected in the prior screens. The slices are displayed in the same order as they are laid out in the device. The current size and maximum available size for each slice are displayed.
+
+GUIDELINES
+
+* You can have only one rpool in the device. And, OpenSolaris will be installed into the rpool. 
+
+* The size of the rpool can be increased up to the maximum available size. When slices are shown as Unused, its available space is displayed in the available (Avail) column. You can change a slice to Unused, making its space available to adjacent slices.
+
+* A red asterisk indicates that slice's content will be destroyed during installation. If the slice is not explicitly altered by the user, the slice content is preserved during installation.
+
+Note: You do not need to set up a mirrored configuration during installation. You can use the ZFS attach command after installation to perform this task. If you plan to set up a mirrored configuration, remember that the second disk has to be equal to or larger than the installation target. 
+
+HOW TO MODIFY SCREEN CONTENT
+
+You can use any of the following options to modify screen content:
+
+     * F5_Change Type - With a partition highlighted, press F5 repeatedly to cycle through the slice types until the desired type is displayed.
+
+     * Editable Fields - If a selected field is highlighted, you can type changes in that field.
+
+     * F7_Reset - Press F7 to restore all data in this screen to the original settings.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the installer screen, use the arrow keys to select the target slice if it is not already selected. If the selected slice type is not a rpool, press F5 repeatedly to cycle through the types until the type, rpool, is displayed. 
+
+IMPORTANT: You can have only one rpool in the device.
+
+OPTIONAL:  You can make further optional modifications to the slice layout as described next, then press F2 to continue to the next screen. The changes you make will be implemented during the installation. To record layout changes, first use the arrow keys to highlight the slice that you want to modify. Then perform any of the following actions:
+
+	* Delete a Slice - Press F5 repeatedly to cycle through the types until the type, Unused, is displayed. When a slice is Unused, its space is made available to adjacent slices.
+
+	* Change a Slice's Type - Press F5 and change the slice type. For example, change the type to rpool. 
+	
+	* Resize a Slice - If a selected slice's size is highlighted, you can resize that slice. Type the new size in the editable field, up to the maximum size available. 
+
+	* Create a New Slice - Select an unused slice. Press F5 and change the slice's type from Unused to another type, such as rpool. 
+
+Note: You can use the F7 key to cancel your changes. 
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/summary.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,33 @@
+INSTALLATION SUMMARY
+
+This screen enables you to review and confirm installation specifications.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the Installation Summary screen, review your installation selections.
+
+OPTIONAL: If you want to change your installation selections, press the F3 key as often as needed to go back to the screens that you want to change. Make your changes in these earlier screens, and then continue through the screens to get back to this Installation Summary.
+
+Press F2 to begin the installation. 
+
+CAUTION: The installation begins when you press F2. Is is recommended that you do not interrupt an installation in progress. An incomplete installation can leave the disk in an indeterminate state.
+
+AFTER INSTALLATION
+
+A progress bar is displayed during the installation. When the installation is complete, a final screen displays the installation results. You can then view the installation log, /tmp/install_log, by pressing F4. 
+
+After a successful installation, you can take either of the following actions: 
+
+     * Within the installer, press F4 to view the installation log. 
+
+     * Reboot to start the newly installed software. After you reboot, you can view the installation log at /var/sadm/system/logs/install_log.	
+
+     * If you want to perform additional tasks before rebooting, press F9 to quit the installer. 
+
+After a failed installation, press F4 to view the installation log. Then, press F9 to quit the installer. Make any corrections that are needed, then restart the installer.
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/timezone.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,19 @@
+TIME ZONE
+
+This series of screens enable you to type the correct time zone for the system to be installed. Select a time zone or location where the computer is typically used. The installer will use the time zone from the computer's internal settings as the default, if possible. 
+
+The installer displays three screens in this series: a Region screen, a Location screen, and a Time Zone screen. 
+
+In the first screen, you choose a general Region, such as Europe. In the next screen, the installer displays locations, such as France or Spain, within the region that you selected. The third screen displays the time zones within the selected location. 
+
+Note: If you select "UTC/GMT" on the Region screen, the Location and Time Zone screens are skipped.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in each installer screen, you can press F2 to accept the default selection. Or, you can use the arrow keys to highlight a different selection, and then press F2 to continue to the next screen.
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/users.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,27 @@
+USERS
+
+In this screen, you can type a root password and define a user account for your installed system.
+
+GUIDELINE
+
+     * Both the root password and user account are optional. But, completing all fields in the screen is recommended.
+
+     * A user account requires only a user name in order for the account to be valid.   
+    
+     * The user name field has the following restrictions:
+          
+          * The user name cannot be root.
+          * The user name must start with a letter.
+          * The user name must contain only letters and numbers.
+
+     * If you type an invalid entry, an error message is displayed for that field.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the Users screen, use the arrow keys to move to each editable field. Type your information in each field. Press F2 to continue to the next screen. 
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/welcome.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,29 @@
+WELCOME
+
+This text installer enables you to install the OpenSolaris Operating System (OS) on SPARC or x86 systems. This installer, in particular, can be used on machines that either do not have or do not need graphics cards.
+
+Note: This initial installation of the OpenSolaris OS overwrites the existing Solaris or OpenSolaris OS with the new version of the OpenSolaris OS. If you want to upgrade an existing OpenSolaris OS, use the pkg(1) command or the Package Manager application instead of this installer. For upgrade instructions, go to the "Getting Started Guide" at opensolaris.com/use, and see the section, "Keeping Your System Up-To-Date," in that Getting Started document.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the Welcome screen, press the F2 key to continue to the next screen.
+
+NAVIGATION
+
+You cannot use a mouse to navigate through the installation screens. Instead, use the function keys for navigation. The available function keys for each screen are listed at the bottom of the screen. For example:
+
+F2_Continue - Press the F2 key to move to the next installation screen. When you press F2, the installer processes any selections or typed entries that you made in that screen.
+F3_Back - Press the F3 key to go back to the previous screen.
+F6_Help - Press the F6 key to view the Help contents for that screen.
+F9_Quit - Press the F9 key to end the installation.
+
+In each screen, use the arrow keys to perform any of the following actions:
+* Moving through the screen text.
+* Changing the highlighted selections.
+* Moving to fields where you need to type information.
+
+Note: If your keyboard does not have function keys, or the keys 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. 
+
+
+
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/x86_fdisk_partitions.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,23 @@
+x86: FDISK PARTITIONS
+
+This screen displays the fdisk partitions for the x86 storage device that you selected in the previous screen. 
+
+Note: The partitions are listed in the order that they exist on the disk. 
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the installer screen, use the arrow keys to highlight either "Use the whole disk" or "Use a partition on the disk". 
+
+     * If you select "Use a partition on the disk," the next screens enable you to select which partition to use for the installation, and, if the partition has defined slices, which slice in that partition to use. You can also adjust the fdisk partition layout. 
+
+     * If you select "Use the whole disk," the installer records that choice and proceeds to the next task.
+
+       CAUTION: "Use the whole disk" erases the entire disk during installation. The disk is overwritten with the new OpenSolaris OS. 
+
+After making your selection, press F2 to continue to the next screen.
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/x86_fdisk_partitions_select.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,61 @@
+x86: SELECT PARTITION
+
+Use this screen to select, create, or modify a Solaris partition to be used for the installation.
+
+This screen enables the user to make adjustments to the fdisk partition layout, such as deleting existing partitions, creating and sizing an extended partition, creating and sizing a Solaris partition, or resizing existing partitions.
+
+The screen displays the existing fdisk partitions. The primary partitions are displayed in the order that they are laid out on the disk. The current size and maximum available size for each partition are displayed. If an extended partition exists, its logical partitions are displayed. The logical partitions are also displayed in the disk layout order within the extended partition.
+
+If the disk has not been previously partitioned, a suggested partitioning is displayed. This suggested partitioning is a single partition that is sized to the whole disk.
+
+GUIDELINES
+
+You can have only one Solaris partition on the device. And, you must use that Solaris partition for the installation. If an existing Solaris partition exists, that partition is selected by default. 
+
+CAUTION: If you reduce a partition size or change its type, the existing partition contents will be erased during installation. Otherwise, existing partition contents are preserved during installation. If your planned changes will destroy a partition during installation, that partition is marked with a red asterisk on this screen. 
+
+HOW TO MODIFY SCREEN CONTENT
+
+You can use any of the following options to modify screen content:
+
+     * F5_Change Type - With a partition highlighted, change the partition type by pressing F5 repeatedly to cycle through the partition types until the desired partition type or Unused is displayed. If Unused is selected, the partition is destroyed, and its space is made available when resizing adjacent partitions.
+
+       Note: You cannot have more than one Solaris partition or more than one extended partition. Therefore, if you have an existing Solaris partition or an existing extended partition, the F5 change options will not include changing the partition to a Solaris partition or an extended partition.
+
+     * Size Fields - If the size field is highlighted, you can type changes in that field.
+
+     * F7_Reset - Press F7 to restore all data in this screen to the original settings.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the installer screen, you have the following options: 
+
+     * If there is an existing Solaris partition, that partition is selected by default. You can do one of the following:
+
+          * You can use the existing partition with its current size. 
+          * You can resize the Solaris partition. The size can be decreased. Or, the size can be increased up to the available space. 
+          * If you want to install to a different partition, you must first delete the existing Solaris partition by changing its type to Unused. Then, you can select another partition and change its type to Solaris. During installation, this modification erases the existing partition contents. 
+
+     * If there is no existing Solaris partition, select a partition and change its type to Solaris. 
+
+     * LINUX-SWAP INSTRUCTIONS: If you used a third-party partitioning tool such as GParted, this screen displays a partition named Linux-swap on which you can install the OpenSolaris OS software. To use this partition, you need to change the type from Linux-swap to Solaris in this screen. Highlight that partition and press F5 repeatedly to cycle through the types until the Solaris type is displayed for that partition.
+
+OPTIONAL: You can make further optional modifications to the partition layout. The changes you make will be implemented during the installation. To record layout changes, first use the arrow keys to highlight the partition that you want to modify. Then perform any of the following actions:
+
+	* Delete a Partition - Press F5 repeatedly to cycle through the partition type options until Unused is displayed. During installation, the initial partition is destroyed, and its space is made available when resizing adjacent partitions.
+
+	* Change a Partition's Type - Press F5 repeatedly to cycle through the partition types until the desired partition type is displayed. For example, change the type to Solaris. 
+	
+	* Resize a Partition - If a selected partition's size is highlighted, you can resize that partition. Type the new size in the editable field, up to the maximum size available. Resizing an existing partition destroys its content.
+
+	* Create a New Partition - Select an unused partition. Press F5 and change the partition's type from Unused to another type, such as Solaris or Extended. 
+
+	* Create an Extended Partition - Press F5 as needed to select the Extended partition type. 
+
+Note: You can press the F7 key to cancel your changes. 
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/x86_fdisk_slices.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,17 @@
+x86: SOLARIS PARTITION SLICES
+
+If Solaris VTOC slices are in a Solaris partition that you selected in the prior screen, this screen lists the VTOC slices. You can choose to install the OpenSolaris OS in one of the slices. Or you can use the whole partition for the installation. 
+
+The existing VTOC slices are displayed in layout order.
+
+Note: If you altered the Solaris partition in the prior screen, this screen is not displayed. 
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the Solaris Partition screen, use the arrow keys to highlight either "Use the whole partition" or "Use a slice in the partition." Press F2 to continue to the next screen. If you plan to use a slice in the partition, the next screen will enable you to select that slice.
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/helpfiles/x86_fdisk_slices_select.txt	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,51 @@
+x86: SELECT SLICE IN SOLARIS PARTITION
+
+This screen enables you to select a VTOC slice in a Solaris partition to use for the installation. To indicate which slice to use for the installation, select the slice and change the slice type to rpool. You have the option of resizing the rpool.
+
+The screen displays the existing slices in the fdisk partition that you selected in the prior screens. The slices are displayed in the order that they are laid out in the partition. The current size and maximum available size for each slice are displayed.
+
+GUIDELINES
+
+* You can have only one rpool in the partition, and OpenSolaris will be installed in the rpool.  
+
+* The size of the rpool can be increased up to the maximum available size. When slices are shown as Unused, its available space is displayed in the available (Avail) column. You can change a slice to Unused, making its space available to adjacent slices.
+
+Note: A red asterisk indicates that slice's content will be destroyed during installation. If the slice is not explicitly altered by the user, the slice content is preserved during installation.
+
+HOW TO MODIFY SCREEN CONTENT
+
+You can use any of the following options to modify screen content:
+
+     * F5_Change Type - With a slice highlighted, press F5 repeatedly to cycle through the types until the desired slice type is displayed.
+
+     * Size Fields - You can type changes in the size fields.
+
+     * F7_Reset - Press F7 to restore all data in this screen to the original settings.
+
+PROCEDURE
+
+To exit this help screen, press F3. Then, in the installer screen, use the arrow keys to select the target slice if it is not already selected. If the selected slice type is not a rpool, press F5 repeatedly to cycle through the slice types until the type, rpool, is displayed. 
+
+Note: Remember that you can have only one rpool in the partition. If another rpool exists, change its type to Unused before you change the targeted slice to a rpool.
+
+OPTIONAL: You can make further optional modifications to the slice layout as described next, then press F2 to continue to the next screen. The changes you make will be implemented during the installation. To record layout changes, first use the arrow keys to highlight the slice that you want to modify. Then perform any of the following actions:
+
+	* Delete a Slice - Press F5 repeatedly to cycle through the slice types until the type, Unused, is displayed. The space from an Unused slice is made available to adjacent slices.
+
+	* Change a Slice's Type - Press F5 repeatedly to cycle through the slice types until the desired type is displayed. Use this procedure, for example, to change the type to rpool. 
+	
+	* Resize a Slice - If a selected slice's size is highlighted, you can resize that slice. Type the new size in the editable field, up to the maximum size available. 
+
+	Note: The sum of the partition's sizes might not equal the size of the whole disk, because partition sizes are rounded to the nearest .1GB, and there might be unused space between partitions. 
+
+	* Create a New Slice - Select an unused slice. Press F5 as needed to change the slice's type from Unused to another type, such as rpool. Slice 2, however, cannot be modified. 
+
+Note: You can use the F7 key to cancel your changes. 
+
+NAVIGATION
+
+Use the function keys listed at the bottom of each screen to navigate between screens. Use the arrow keys to move through the text on each screen.
+
+Note: If your keyboard does not have function keys, or the keys do not respond, press ESC to view the alternate ESC keys for navigation.
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/__init__.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,7 @@
+'''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
+SUNWinstall
+'''
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,78 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+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 \
+		ip_address.py \
+		network_info.py \
+		partition_info.py \
+		slice_info.py \
+		system_info.py \
+		user_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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/disk_info.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,629 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+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]))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/disk_space.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,125 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/install_profile.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,57 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+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.
+'''
+
+
+class InstallProfile(object):
+    '''
+    Represents an entire installation profile
+    '''
+    
+    TAG = "install_profile"
+    
+    def __init__(self, disk=None, nic=None, system=None, users=None,
+                 zpool=None):
+        self.disk = disk
+        self.nic = nic
+        self.system = system
+        if users is None:
+            users = []
+        self.users = users
+        self.zpool = zpool
+    
+    def __str__(self):
+        result = ["Install Profile:"]
+        result.append(str(self.disk))
+        result.append(str(self.nic))
+        result.append(str(self.system))
+        for user in self.users:
+            result.append(str(user))
+        result.append(str(self.zpool))
+        return "\n".join(result)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/ip_address.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,92 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Class representing IP Addresses
+'''
+
+class IPAddress(object):
+    '''Simple class to represent IP addresses
+    
+    This implementation represents purely the IP. Netmask, if needed,
+    should be represented by a second IPAddress.
+    
+    '''
+    
+    DEFAULT = "0.0.0.0"
+    
+    def __init__(self, address=None):
+        if address is not None:
+            address = IPAddress.convert_address(address)
+        self._address = address
+    
+    def __str__(self):
+        return self.get_address()
+    
+    def get_address(self):
+        '''Returns this IP address as a string'''
+        segments = []
+        for segment in self._address:
+            segments.append(str(segment))
+        return ".".join(segments)
+    
+    def set_address(self, address):
+        '''Sets this IPAddress' address'''
+        if address is not None:
+            address = IPAddress.convert_address(address)
+        self._address = address
+    
+    address = property(get_address, set_address)
+    
+    @staticmethod
+    def convert_address(address):
+        '''Convert a string into an array of ints. Also serves as a
+        validation function - strings not of the correct form will raise
+        a ValueError
+        
+        '''
+        segments = IPAddress.incremental_check(address)
+        if len(segments) != 4:
+            raise ValueError("Bad length")
+        return segments
+    
+    @staticmethod
+    def incremental_check(address):
+        '''Incrementally check an IP Address. Useful for checking a partial
+        address, e.g., one that is partly typed into the UI
+        
+        '''
+        ip = address.split(".")
+        segments = []
+        if len(ip) > 4:
+            raise ValueError("Too many octets")
+        for segment in ip:
+            if not segment:
+                continue
+            int_seg = int(segment)
+            if int_seg < 0 or int_seg > 255:
+                raise ValueError("Values should be between 0 and 255")
+            else:
+                segments.append(int_seg)
+        return segments
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/network_info.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,194 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Class and functions supporting representing a NIC and locating
+the NICs installed on the system by name (using dladm)
+'''
+
+import logging
+from subprocess import Popen, PIPE
+
+from osol_install.profile.ip_address import IPAddress
+
+
+class NetworkInfo(object):
+    '''Represents a NIC and its network settings'''
+    
+    AUTOMATIC = "automatic"
+    MANUAL = "manual"
+    NONE = "none"
+    DEFAULT_NETMASK = "255.255.255.0"
+    
+    ETHER_NICS = None
+    
+    @staticmethod
+    def find_links():
+        '''Use dladm show-ether to find the physical ethernet links
+        on the system
+        
+        '''
+        
+        if NetworkInfo.ETHER_NICS is not None:
+            return NetworkInfo.ETHER_NICS
+        
+        argslist = ['/usr/sbin/dladm', 'show-ether', '-o', 'LINK', '-p']
+        
+        try:
+            (nic_list, dladm_err) = Popen(argslist, stdout=PIPE,
+                                          stderr=PIPE).communicate()
+        except OSError, err:
+            logging.warn("OSError occurred: %s", err)
+            return []
+        if dladm_err:
+            logging.warn("Error occurred during call to dladm: %s", dladm_err)
+        # pylint: disable-msg=E1103
+        # nic_list is a string
+        NetworkInfo.ETHER_NICS = nic_list.splitlines()
+        NetworkInfo.ETHER_NICS.sort()
+        return NetworkInfo.ETHER_NICS
+
+    def __init__(self, nic_name=None, net_type=None, ip_address=None,
+                 netmask=None, gateway=None, dns_address=None, domain=None):
+        self.nic_name = nic_name
+        self.type = net_type
+        self.ip_address = ip_address
+        if netmask is None:
+            netmask = NetworkInfo.DEFAULT_NETMASK
+        self.netmask = netmask
+        self.gateway = gateway
+        self.dns_address = dns_address
+        self.domain = domain
+        self.find_defaults = True
+    
+    def __str__(self):
+        result = ["NIC %s:" % self.nic_name]
+        result.append("Type: %s" % self.type)
+        if self.type == NetworkInfo.MANUAL:
+            result.append("IP: %s" % self.ip_address)
+            result.append("Netmask: %s" % self.netmask)
+            result.append("Gateway: %s" % self.gateway)
+            result.append("DNS: %s" % self.dns_address)
+            result.append("Domain: %s" % self.domain)
+        return "\n".join(result)
+    
+    def find_dns(self):
+        '''Try to determine the DNS info of the NIC if DHCP is running
+        Returns True if this action was successful
+        
+        '''
+        dns_server = self._run_dhcpinfo("DNSserv")
+        if dns_server:
+            self.dns_address = dns_server
+            return True
+        else:
+            return False
+    
+    def find_gateway(self):
+        '''Try to determine the router of the NIC if DHCP is running
+        Returns True if this action was successful
+        
+        '''
+        gateway = self._run_dhcpinfo("Router")
+        if gateway:
+            self.gateway = gateway
+            return True
+        else:
+            return False
+    
+    def find_domain(self):
+        '''Try to determine the domain info of the NIC if DHCP is running
+        Returns True if this action was successful
+        
+        '''
+        domain = self._run_dhcpinfo("DNSdmain")
+        if domain:
+            self.domain = domain
+            return True
+        else:
+            return False
+    
+    def find_netmask(self):
+        '''Try to determine the netmask info of the NIC if DHCP is running
+        Returns True if this action was successful
+        
+        '''
+        netmask = self._run_dhcpinfo("Subnet")
+        if netmask:
+            self.netmask = IPAddress(netmask)
+            return True
+        else:
+            return False
+    
+    def get_ifconfig_data(self):
+        '''Returns a dictionary populated with the data returned from ifconfig
+        Returns None if the call to ifconfig fails in some way
+        
+        '''
+
+        argslist = ['/sbin/ifconfig', self.nic_name]
+        try:
+            (ifconfig_out, ifconfig_err) = Popen(argslist, stdout=PIPE,
+                                                 stderr=PIPE).communicate()
+        except OSError, err:
+            logging.warn("Failed to call ifconfig: %s", err)
+            return None
+        if ifconfig_err:
+            logging.warn("Error occurred during call to ifconfig: %s",
+                         ifconfig_err)
+            return None
+        # pylint: disable-msg=E1103
+        # ifconfig_out is a string
+        ifconfig_out = ifconfig_out.split()
+        link_data = {}
+        link_data['flags'] = ifconfig_out[1]
+        ifconfig_out = ifconfig_out[2:]
+        for i in range(len(ifconfig_out) / 2):
+            link_data[ifconfig_out[2*i]] = ifconfig_out[2*i+1]
+        return link_data
+    
+    def _run_dhcpinfo(self, code):
+        '''Run the dhcpinfo command against this NIC, requesting 'code' '''
+        ifconfig_data = self.get_ifconfig_data()
+        if not ifconfig_data or ifconfig_data['flags'].count("DHCP") == 0:
+            logging.warn("This connection not using DHCP")
+            return None
+        
+        argslist = ['/sbin/dhcpinfo',
+                    '-i', self.nic_name,
+                    '-n', '1',
+                    code]
+        try:
+            (dhcpout, dhcperr) = Popen(argslist, stdout=PIPE,
+                                       stderr=PIPE).communicate()
+        except OSError, err:
+            logging.warn("OSError ocurred during dhcpinfo call: %s", err)
+            return None
+        
+        if dhcperr:
+            logging.warn("Error ocurred during dhcpinfo call: ", dhcperr)
+        
+        # pylint: disable-msg=E1103
+        # dhcpout is a string
+        return dhcpout.rstrip("\n")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/partition_info.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,648 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/slice_info.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,467 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+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()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/system_info.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,116 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Represent Systemwide attributes such as timezone and locale 
+'''
+
+import locale
+import logging
+
+
+class SystemInfo(object):
+    '''
+    Represents miscellaneous system information
+    '''
+    
+    DEFAULT_HOSTNAME = "opensolaris"
+    UTC = "UTC"
+    
+    DEFAULT_LOCALE = "C"
+    DEFAULT_ACTUAL_LOCALE = "C/POSIX"
+
+    def __init__(self, hostname=None, tz_region=None,
+                 tz_country=None, tz_timezone=None, time_offset=0,
+                 keyboard=None, locale=None, actual_lang=None):
+        if hostname is None:
+            hostname = SystemInfo.DEFAULT_HOSTNAME
+        self.hostname = hostname
+        self.tz_region = tz_region
+        self.tz_country = tz_country
+        self.tz_timezone = tz_timezone
+        self.time_offset = time_offset
+        self.keyboard = keyboard
+        self.locale = locale
+        self.actual_lang = actual_lang 
+    
+    def __str__(self):
+        result = ["System Info:"]
+        result.append("\nHostname: ")
+        result.append(str(self.hostname))
+        result.append("\nTZ: ")
+        result.append(str(self.tz_region))
+        result.append(" - ")
+        result.append(str(self.tz_country))
+        result.append(" - ")
+        result.append(str(self.tz_timezone))
+        result.append("\nTime Offset: ")
+        result.append(str(self.time_offset))
+        result.append("\nKeyboard: ")
+        result.append(str(self.keyboard))
+        result.append("\nLocale: ")
+        result.append(str(self.locale))
+        return "".join(result)
+    
+    @staticmethod
+    def get_actual_lang(locale):
+        '''Determine the human readable language from the locale
+
+        '''
+
+        try:
+            fp = open("/usr/share/gui-install/langs_localized")
+        except:
+            raise ValueError(
+                "Unable to open /usr/share/gui-install/langs_localized")
+        
+        for line in fp:
+            key, splitter, val = line.partition(":")
+            if key == locale:
+                return (val.rstrip())
+
+        raise ValueError("Unsupported language for locale " + locale)
+ 
+    def determine_locale(self):
+        '''Read in the language set during boot.'''
+        # getdefaultlocale() returns a tuple such as ('en_US', 'UTF8')
+        # The second portion of that tuple is not formatted correctly for
+        # processing, so use getpreferredencoding() to get the encoding.
+        language = locale.getdefaultlocale()[0]
+        encoding = locale.getpreferredencoding()
+        
+        if language is None:
+            self.locale = SystemInfo.DEFAULT_LOCALE
+            self.actual_lang = SystemInfo.DEFAULT_ACTUAL_LOCALE
+        else:
+            if encoding:
+                self.locale = ".".join([language, encoding])
+            else:
+                self.locale = language
+            try:
+                self.actual_lang = self.get_actual_lang(self.locale)
+            except ValueError, err:
+                logging.warn(err)
+                self.actual_lang = self.locale
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/profile/user_info.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,90 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+'''
+Representation of a user on the system
+'''
+
+from osol_install.install_utils import encrypt_password
+
+class UserInfo(object):
+    '''Describes a single user's login data'''
+    
+    def __init__(self, real_name=None, login_name=None, password=None,
+                 encrypted=False, is_role=False):
+        self.real_name = real_name
+        self.login_name = login_name
+        self._password = None
+        self.passlen = None
+        self.set_password(password, encrypted=encrypted)
+        self.is_role = is_role
+    
+    def is_valid(self):
+        '''This UserInfo is valid if and only if both the username
+        and password are valid
+        
+        '''
+        return self.is_username_valid() and self.is_password_valid()
+    
+    def is_username_valid(self):
+        '''Returns True if self.login_name is a non-empty string'''
+        return bool(self.login_name)
+    
+    def get_password(self):
+        '''Returns the (encrypted) password'''
+        return self._password
+    
+    def set_password(self, password, encrypted=False):
+        '''Set the password, encrypting it unless this function
+        is explicitly called with encrypted=True
+        
+        '''
+        if password is None:
+            self._password = None
+            self.passlen = 0
+            return
+        
+        if not encrypted:
+            self._password = encrypt_password(password)
+            self.passlen = len(password)
+        else:
+            self._password = password
+            self.passlen = 16
+    
+    password = property(get_password, set_password)
+    
+    def is_password_valid(self):
+        '''Empty string is valid; 'None' indicates that password 
+        needs to be set first
+        
+        '''
+        return (self._password is not None)
+    
+    def __str__(self):
+        result = ["User Info(%s):" % self.login_name]
+        result.append("Real name: %s" % self.real_name)
+        result.append("Login name: %s" % self.login_name)
+        result.append("Is Role: %s" % str(self.is_role))
+        return "\n".join(result)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,111 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../../../Makefile.cmd
+
+all:=		TARGET= all
+clean:=		TARGET= clean
+clobber:=	TARGET= clobber
+install:=	TARGET= install
+
+MSG_DOMAIN =	textinstall
+
+PROGS=		text-install
+
+PYMODULES=	__init__.py \
+		action.py \
+		base_screen.py \
+		color_theme.py \
+		date_time.py \
+		disk_selection.py \
+		disk_window.py \
+		edit_field.py \
+		error_window.py \
+		fdisk_partitions.py \
+		help_screen.py \
+		inner_window.py \
+		install_progress.py \
+		install_status.py \
+		list_item.py \
+		log_viewer.py \
+		main_window.py \
+		network_nic_configure.py \
+		network_nic_select.py \
+		network_type.py \
+		partition_edit_screen.py \
+		screen_list.py \
+		scroll_window.py \
+		summary.py \
+		ti_install.py \
+		ti_install_utils.py \
+		timezone.py \
+		users.py \
+		welcome.py \
+		window_area.py
+
+PYCMODULES=     $(PYMODULES:%.py=%.pyc)
+
+ROOTPROGS=      $(PROGS:%=$(ROOTUSRBIN)/%)
+
+ROOTPYMODULES=  $(PYMODULES:%=$(ROOTPYTHONVENDORINSTALLTI)/%)
+
+ROOTPYCMODULES= $(PYCMODULES:%=$(ROOTPYTHONVENDORINSTALLTI)/%)
+
+MSGFILES =	$(PYMODULES) text_install.py
+
+.KEEP_STATE:
+
+all:		python $(PROGS)
+
+clean:
+	rm -f $(PROGS) *.pyc  $(MSG_DOMAIN).po
+
+clobber: clean
+
+
+install: all .WAIT $(ROOTPROGS) \
+	$(ROOTPYTHONVENDOR) \
+	$(ROOTPYTHONVENDORINSTALL) \
+	$(ROOTPYTHONVENDORINSTALLTI) \
+	$(ROOTPYMODULES) \
+	$(ROOTPYCMODULES) \
+	.WAIT msgs
+
+python:
+	$(PYTHON) -m compileall -l $(@D)
+
+text-install:	text_install.py
+		cp text_install.py text-install
+
+msgs:	$(MSG_DOMAIN).po
+
+$(MSG_DOMAIN).po: text_install.py $(PYMODULES)
+	@echo "Making messages file $(MSG_DOMAIN).po"
+	$(GNUXGETTEXT) $(GNUXGETFLAGS) -d $(MSG_DOMAIN) \
+		$(MSGFILES)
+
+FRC:
+
+include ../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/__init__.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,60 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+'''Set "_" to be the character that flags text that should be
+extracted by xgettext for translation"
+
+Set the ESCDELAY environment variable, if it's not yet set
+(n)curses will wait ESCDELAY milliseconds after receiving an
+ESC key as input before processing the input. It defaults to 1000 ms
+(1 sec), which causes function and arrow keys to react very slowly, so
+we default to 100 instead. (Settings of '0' interfere with tipline
+esc-sequences)
+
+'''
+
+
+import gettext
+from os import putenv, getenv
+
+
+_ = gettext.translation("textinstall", "/usr/share/locale",
+                        fallback=True).gettext
+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)s - %(levelname)-8s: "
+              "%(filename)s:%(lineno)d %(message)s")
+LOG_LEVEL_INPUT = 5
+LOG_NAME_INPUT = "INPUT"
+
+
+ESCDELAY = getenv("ESCDELAY")
+try:
+    int(ESCDELAY)
+except (TypeError, ValueError):
+    putenv("ESCDELAY", "100")
+del ESCDELAY
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/action.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,69 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Contains the 'Action' class
+'''
+
+class Action(object):
+    '''An Action represents the combination of F# key, descriptive text,
+    and, in some cases, an associated arbitrary function.
+    
+    '''
+    
+    def _do_action(self, screen=None):
+        '''Private default function assigned to do_action'''
+        raise NotImplementedError, "Must override do_action before use"
+    
+    def __init__(self, key, text, do_action=None):
+        '''
+        Constructor
+        
+        key (required): An integer corresponding to a function key.
+        When the function key is pressed and handled by a MainWindow,
+        do_action will be invoked with the current screen as its sole
+        parameter.
+        
+        For example, key=curses.KEY_F2 would imply this action is
+        associated with F2 (and Esc-2)
+        
+        text (required): A string description of the action. This is displayed
+        in the footer. Keep it short - only 80 characters are available for all
+        actions, and it must be assumed that the 'long notation' of
+        ESC-#_<description> is printed for each action.
+        
+        do_action (optional): If supplied, this parameter should be a 
+        function that accepts a single parameter. The function will be
+        passed the current screen as the parameter, and should return the
+        next screen to be shown. If not supplied, the corresponding F# key
+        MUST be caught in a subwindow.
+        
+        '''
+        
+        self.key = key
+        self.text = text
+        if do_action is not None:
+            self.do_action = do_action
+        else:
+            self.do_action = self._do_action
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/base_screen.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,216 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Common screen functionality for text installer UI
+'''
+
+from osol_install.text_install import _
+
+class QuitException(StandardError):
+    '''Raised when a function needs to force the program to quit gracefully'''
+    pass
+
+
+class RebootException(SystemExit):
+    '''Raised when user requests reboot'''
+    pass
+
+
+class SkipException(StandardError):
+    '''Raised to signal this screen should be skipped'''
+    pass
+
+
+class UIMessage(StandardError):
+    '''Exception class for passing an error message to the UI'''
+    
+    def get_message(self):
+        if self.args and self.args[0]:
+            return self.args[0]
+        else:
+            return ""
+    
+    message = property(get_message)
+
+
+class BaseScreen(object):
+    '''Abstract base class for screens, providing some common
+    functionality for all screens.
+    
+    HEADER_TEXT: Default header text for this screen. Screens which have
+    permanent, static headers can define this variable at the class level.
+    Dynamically titled screens should set the default here, and override
+    self.header_text at the instance level as needed.
+    
+    '''
+    
+    HEADER_TEXT = "DEFAULT TEXT"
+    CONFIRM_QUIT_HEADER = _("Confirm: Quit the Installer?")
+    QUIT_TEXT = _("Do you want to quit the Installer?")
+    QUIT_DISK_MOD_TEXT = _("Do you want to quit the Installer?\n\n"
+                           "Any changes made to the disk by the "
+                           "Installer will be left \"as is.\"")
+    CANCEL_BUTTON = _("Cancel")
+    CONFIRM_BUTTON = _("Quit")
+    
+    def __init__(self, main_win):
+        '''Set main_win and store win_size_y and win_size_x'''
+        self.instance = ""
+        self.main_win = main_win
+        self.center_win = self.main_win.central_area
+        self._win_size = self.center_win.window.getmaxyx()
+        self.header_text = self.HEADER_TEXT
+        self.install_profile = None
+        self.orig_border = (0, 0)
+    
+    def get_win_size_y(self):
+        '''Return the window size, adjusted based on the specified border'''
+        return self._win_size[0] - self.center_win.border_size[0] * 2
+    
+    def get_win_size_x(self):
+        '''Return the window size, adjusted based on the specified border'''
+        return self._win_size[1] - self.center_win.border_size[1] * 2
+    
+    win_size_x = property(get_win_size_x)
+    win_size_y = property(get_win_size_y)
+    
+    def set_actions(self):
+        '''Subclasses of BaseScreen should override this function to
+        add/remove Actions from their attached main_win object
+        
+        '''
+        pass
+    
+    def show(self, install_profile):
+        '''Wrapper method for common entry/exit functionality into _show.
+        This method performs the common tasks of clearing the main_win of
+        the previous screen's objects, resetting and setting the actions,
+        and setting the header_text.
+        
+        This method then call's _show, which should be overridden by the
+        subclass.
+        
+        '''
+        self.install_profile = install_profile
+        self.orig_border = self.center_win.border_size
+        try:
+            self.main_win.clear()
+            self.set_actions()
+            self.main_win.show_actions()
+            self.main_win.set_header_text(self.header_text)
+            
+            self._show()
+            self.main_win.do_update()
+            return self.validate_loop()
+        except QuitException:
+            return None
+        except SkipException:
+            return self.main_win.screen_list.get_next(self, skipped=True)
+        finally:
+            self.center_win.border_size = self.orig_border
+    
+    def _show(self):
+        '''Abstract base method. Subclasses should override this method to
+        set-up any lists, editable fields, or text relevant to this screen
+        
+        '''
+        raise NotImplementedError, "Subclasses must override the 'show' method"
+    
+    def validate_loop(self):
+        '''
+        Validation loop. Runs main_win.process_input to accept user input
+        while the screen is active. When the user tries to move to another
+        screen, validate (if moving onward), save state by calling
+        on_change_screen and either on_prev or on_continue.
+        '''
+        continue_validate = True
+        while continue_validate:
+            next_screen = self.main_win.process_input(self)
+            if (self.main_win.screen_list.peek_last() == self and
+                next_screen != self.main_win.screen_list.help):
+                try:
+                    self.validate()
+                    continue_validate = False
+                    self.on_continue()
+                except UIMessage as msg:
+                    self.main_win.screen_list.previous_screen()
+                    error_str = str(msg)
+                    if error_str:
+                        self.main_win.error_line.display_err(error_str)
+            elif next_screen is None:
+                if self.confirm_quit():
+                    raise QuitException
+            else:
+                continue_validate = False
+                self.on_prev()
+        self.on_change_screen()
+        self.center_win.make_inactive()
+        return next_screen
+    
+    def confirm_quit(self):
+        '''Confirm the user truly wants to quit. Can be overridden by
+        sub-classes needing to do any clean-up, such as signaling other
+        threads to shutdown.
+        
+        '''
+        return self.main_win.pop_up(BaseScreen.CONFIRM_QUIT_HEADER,
+                                    BaseScreen.QUIT_TEXT,
+                                    BaseScreen.CANCEL_BUTTON,
+                                    BaseScreen.CONFIRM_BUTTON)
+    
+    def validate(self):
+        '''
+        This function is called whenever the user tries to continue forward.
+        Screens should override this function to do any final checks for data
+        validity. If any problems are found, a UIMessage should be raised,
+        with a string indicating the issue. The string will be displayed to the
+        screen (and must be 78 characters or less)
+        '''
+        pass
+    
+    def on_prev(self):
+        '''
+        Called prior to leaving this screen, but only if quitting or moving to
+        the prior screen. This function should be overridden if data needs to
+        be preserved differently if the user is going 'back' instead of
+        'forward'
+        '''
+        pass
+    
+    def on_continue(self):
+        '''
+        Called prior to leaving this screen, but only if moving to the next
+        screen. This function should be overridden if data needs to be
+        preserved differently if the user is going 'forward' instead of 'back'
+        '''
+        pass
+    
+    def on_change_screen(self):
+        '''
+        Called prior to leaving this screen, regardless of direction. Most data
+        preservation should be done here, unless the data needs to be handled
+        differently depending on the direction the user is going.
+        '''
+        pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/color_theme.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,140 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Represent sets of curses background attributes as a 'theme' for the various
+UI pieces of the text installer 
+'''
+
+
+import curses
+
+
+class ColorTheme(object):
+    '''Represents a 'theme' for the text installer
+    
+    Note that 'color' can be any combination of curses attributes,
+    not just color (e.g. bold, underline, etc)
+    
+    Note that attributes get OR'ed with any additional attributes. This means
+    in the case of non-color attributes such as A_REVERSE and A_BOLD,
+    they can't be removed easily in a temporary fashion.
+    
+    '''
+    
+    def __init__(self, border=None, header=None, default=None, edit_field=None,
+                 highlight_edit=None, list_field=None, error_msg=None,
+                 inactive=None, progress_bar=None, force_bw=False):
+        '''curses.start_color() must be called prior to instantiation of a
+        ColorTheme, if the terminal supports colors. Terminals that don't
+        support color are given a black and white theme.
+        
+        force_bw - If true, uses a black and white color theme, regardless of
+                   whether the current terminal supports colors
+        
+        All other parameters should be either a positive integer, representing
+        a bitwise OR of desired curses attributes for UI elements of that type,
+        or None, in which case a default value is chosen.
+        
+        '''
+        has_colors = curses.has_colors() and not force_bw
+        
+        if default is not None:
+            self.default = default
+        else:
+            if has_colors:
+                curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
+                self.default = curses.color_pair(1) | curses.A_BOLD
+            else:
+                self.default = 0
+        
+        if border is not None:
+            self.border = border
+        else:
+            if has_colors:
+                curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_CYAN)
+                self.border = curses.color_pair(2) | curses.A_BOLD
+            else:
+                self.border = curses.A_REVERSE
+        
+        if header is not None:
+            self.header = header
+        else:
+            if has_colors:
+                curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_BLUE)
+                self.header = curses.color_pair(3) | curses.A_BOLD
+            else:
+                self.header = curses.A_REVERSE
+        
+        if edit_field is not None:
+            self.edit_field = edit_field
+        else:
+            if has_colors:
+                self.edit_field = self.default
+            else:
+                self.edit_field = self.default
+        
+        if highlight_edit is not None:
+            self.highlight_edit = highlight_edit
+        else:
+            if has_colors:
+                curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_BLUE)
+                self.highlight_edit = curses.color_pair(4) | curses.A_BOLD
+            else:
+                self.highlight_edit = curses.A_REVERSE | curses.A_BOLD
+        
+        if list_field is not None:
+            self.list_field = list_field
+        else:
+            if has_colors:
+                curses.init_pair(5, curses.COLOR_WHITE, curses.COLOR_CYAN)
+                self.list_field = curses.color_pair(5) | curses.A_BOLD
+            else:
+                self.list_field = curses.A_REVERSE | curses.A_BOLD
+        
+        if error_msg is not None:
+            self.error_msg = error_msg
+        else:
+            if has_colors:
+                curses.init_pair(6, curses.COLOR_WHITE, curses.COLOR_RED)
+                self.error_msg = curses.color_pair(6) | curses.A_BOLD
+            else:
+                self.error_msg = curses.A_REVERSE
+        
+        if inactive is not None:
+            self.inactive = inactive
+        else:
+            if has_colors:
+                self.inactive = self.error_msg | curses.A_REVERSE
+            else:
+                self.inactive = 0
+        
+        if progress_bar is not None:
+            self.progress_bar = progress_bar
+        else:
+            if has_colors:
+                curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_RED)
+                self.progress_bar = curses.color_pair(7)
+            else:
+                self.progress_bar = curses.A_REVERSE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/date_time.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,513 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Gather Date and Time information from the user
+'''
+
+import calendar
+import datetime
+import logging
+import os
+
+from osol_install.text_install import _, LOG_LEVEL_INPUT
+from osol_install.text_install.base_screen import BaseScreen, UIMessage
+from osol_install.text_install.edit_field import EditField
+from osol_install.text_install.error_window import ErrorWindow
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.window_area import WindowArea
+
+
+class DateTimeScreen(BaseScreen):
+    '''
+    Allow user to select year, month, day, hour, and minute to be
+    used to set system clock.
+    '''
+    
+    HEADER_TEXT = _("Date and Time")
+    
+    YEAR_TEXT = _("Year:")
+    MONTH_TEXT = _("Month:")
+    DAY_TEXT = _("Day:")
+    HOUR_TEXT = _("Hour:")
+    MINUTE_TEXT = _("Minute:")
+    YEAR_FORMAT = _("(YYYY)")
+    
+    PARAGRAPH = _("Edit the date and time as necessary.\n"
+                  "The time is in 24 hour format.")
+    
+    YEAR_DIGITS = 4
+    TWO_DIGITS = 2
+    YEAR_LEN = len(YEAR_TEXT)
+    MONTH_LEN = len(MONTH_TEXT)
+    DAY_LEN = len(DAY_TEXT)
+    HOUR_LEN = len(HOUR_TEXT)
+    MINUTE_LEN = len(MINUTE_TEXT)
+    MAX_LEN = max(YEAR_LEN, MONTH_LEN, DAY_LEN, HOUR_LEN, MINUTE_LEN) + 1
+    
+    ITEM_OFFSET = 2
+    
+    def __init__(self, main_win):
+        super(DateTimeScreen, self).__init__(main_win)
+        
+        year_edit_width = DateTimeScreen.YEAR_DIGITS + 1
+        list_width = DateTimeScreen.MAX_LEN + year_edit_width
+        self.list_area = WindowArea(1, list_width, 0,
+                                    DateTimeScreen.ITEM_OFFSET)
+        self.year_edit_area = WindowArea(1, year_edit_width, 0,
+                                         DateTimeScreen.MAX_LEN + 1)
+        other_edit_width = DateTimeScreen.TWO_DIGITS + 1
+        other_edit_offset = (DateTimeScreen.MAX_LEN +
+                             (DateTimeScreen.YEAR_DIGITS -
+                              DateTimeScreen.TWO_DIGITS) + 1)
+        self.edit_area = WindowArea(1, other_edit_width, 0, other_edit_offset)
+        self.info_offset = (DateTimeScreen.ITEM_OFFSET +
+                            self.list_area.columns + 1)
+        self.info_width = len(DateTimeScreen.YEAR_FORMAT)
+        err_offset = self.info_offset + self.info_width + 2
+        err_width = self.win_size_x - err_offset
+        self.err_area = WindowArea(1, err_width, 0, err_offset)
+        
+        self.year_edit = None
+        self.year_err = None
+        self.year_list = None
+        self.month_edit = None
+        self.month_err = None
+        self.month_list = None
+        self.day_edit = None
+        self.day_err = None
+        self.day_list = None
+        self.hour_edit = None
+        self.hour_err = None
+        self.hour_list = None
+        self.minute_edit = None
+        self.minute_err = None
+        self.minute_list = None
+        self.year_is_valid = True
+        self.month_is_valid = True
+        self.date_range_loc = None
+        self.saved_year = None
+        self.saved_month = None
+        self.saved_day = None
+        self.saved_hour = None
+        self.saved_minute = None
+        self.saved_days_in_month = None
+    
+    def _show(self):
+        '''
+        Prepare the editable fields for day, month, year, hour and minute
+        
+        '''
+        y_loc = 1
+        
+        y_loc += self.center_win.add_paragraph(DateTimeScreen.PARAGRAPH, y_loc)
+        
+        
+        os.environ["TZ"] = self.install_profile.system.tz_timezone
+        now = datetime.datetime.now()
+        logging.debug("now year month day hour minute: %s %s %s %s %s",
+                      now.year, now.month, now.day, now.hour, now.minute)
+        
+        # Only update saved values if this is first time on screen or
+        # if we have saved offset in profile (F2, return to screen)
+        #
+        update_vals = False
+        if self.saved_year is None:
+            update_vals = True
+            showtime = now
+        elif self.install_profile.system.time_offset != 0:
+            showtime = now +  self.install_profile.system.time_offset
+            update_vals = True
+            self.install_profile.system.time_offset = 0
+        
+        if update_vals:
+            self.saved_year = str(showtime.year)
+            self.saved_month = str(showtime.month)
+            self.saved_day = str(showtime.day)
+            self.saved_hour = str(showtime.hour)
+            self.saved_minute = str(showtime.minute)
+            self.saved_days_in_month = calendar.monthrange(showtime.year,
+                                                           showtime.month)[1]
+            
+        logging.debug("starting year month day hour minute:_%s_%s_%s_%s_%s",
+                      self.saved_year, self.saved_month, self.saved_day,
+                      self.saved_hour, self.saved_minute)
+        logging.debug("starting days_in_month: %s", self.saved_days_in_month)
+        
+        
+        y_loc += 1
+        self.err_area.y_loc = y_loc
+        self.list_area.y_loc = y_loc
+        
+        self.year_err = ErrorWindow(self.err_area, window=self.center_win,
+                                    centered=False)
+        self.year_list = ListItem(self.list_area,
+                                  window=self.center_win,
+                                  text=DateTimeScreen.YEAR_TEXT)
+        self.year_edit = EditField(self.year_edit_area, window=self.year_list,
+                                   validate=year_valid,
+                                   error_win=self.year_err,
+                                   on_exit=year_on_exit,
+                                   text=self.saved_year)
+        self.year_edit.clear_on_enter = True
+        
+        self.center_win.add_text(DateTimeScreen.YEAR_FORMAT, y_loc,
+                                 self.info_offset)
+        
+        y_loc += 1
+        self.err_area.y_loc = y_loc
+        self.list_area.y_loc = y_loc
+        
+        self.month_err = ErrorWindow(self.err_area, window=self.center_win,
+                                    centered=False)
+        self.month_list = ListItem(self.list_area, window=self.center_win,
+                                   text=DateTimeScreen.MONTH_TEXT)
+        self.month_edit = EditField(self.edit_area, window=self.month_list,
+                                    validate=month_valid,
+                                    error_win=self.month_err,
+                                    on_exit=month_on_exit,
+                                    text=self.saved_month,
+                                    numeric_pad="0")
+        self.month_edit.clear_on_enter = True
+        self.center_win.add_text("(1-12)", y_loc, self.info_offset)
+        
+        y_loc += 1
+        self.err_area.y_loc = y_loc
+        self.list_area.y_loc = y_loc
+        
+        self.day_err = ErrorWindow(self.err_area, window=self.center_win,
+                                   centered=False)
+        self.day_list = ListItem(self.list_area,
+                                 window=self.center_win,
+                                 text=DateTimeScreen.DAY_TEXT)
+        self.day_edit = EditField(self.edit_area, window=self.day_list,
+                                  validate=day_valid,
+                                  error_win=self.day_err,
+                                  on_exit=day_on_exit,
+                                  text=self.saved_day,
+                                  numeric_pad="0")
+        self.day_edit.clear_on_enter = True
+        
+        self.month_edit.validate_kwargs["date_time"] = self
+        self.month_edit.validate_kwargs["year_edit"] = self.year_edit
+        self.month_edit.validate_kwargs["day_edit"] = self.day_edit
+        
+        self.year_edit.validate_kwargs["date_time"] = self
+        self.year_edit.validate_kwargs["month_edit"] = self.month_edit
+        self.year_edit.validate_kwargs["day_edit"] = self.day_edit
+        
+        self.day_edit.validate_kwargs["date_time"] = self
+        self.day_edit.validate_kwargs["year_edit"] = self.year_edit
+        self.day_edit.validate_kwargs["month_edit"] = self.month_edit
+        self.date_range_loc = (y_loc, self.info_offset)
+        self.update_day_range(self.saved_days_in_month)
+        
+        y_loc += 1
+        self.err_area.y_loc = y_loc
+        self.list_area.y_loc = y_loc
+        
+        self.hour_err = ErrorWindow(self.err_area, window=self.center_win,
+                                    centered=False)
+        self.hour_list = ListItem(self.list_area, window=self.center_win,
+                                  text=DateTimeScreen.HOUR_TEXT)
+        self.hour_edit = EditField(self.edit_area, window=self.hour_list,
+                                   validate=hour_valid,
+                                   error_win=self.hour_err,
+                                   on_exit=hour_on_exit,
+                                   text=self.saved_hour,
+                                   numeric_pad="0")
+        self.hour_edit.clear_on_enter = True
+        self.center_win.add_text("(0-23)", y_loc, self.info_offset)
+        
+        y_loc += 1
+        self.err_area.y_loc = y_loc
+        self.list_area.y_loc = y_loc
+        
+        self.minute_err = ErrorWindow(self.err_area, window=self.center_win,
+                                      centered=False)
+        self.minute_list = ListItem(self.list_area, window=self.center_win,
+                                    text=DateTimeScreen.MINUTE_TEXT)
+        self.minute_edit = EditField(self.edit_area,
+                                     window=self.minute_list,
+                                     validate=minute_valid,
+                                     error_win=self.minute_err,
+                                     on_exit=minute_on_exit,
+                                     text=self.saved_minute,
+                                     numeric_pad="0")
+        self.minute_edit.clear_on_enter = True
+        self.center_win.add_text("(0-59)", y_loc, self.info_offset)
+        
+        self.main_win.do_update()
+        self.center_win.activate_object(self.year_list)
+    
+    def validate(self):
+        '''Verify each of the edit fields'''
+        year_value = self.year_edit.get_text()
+        month_value = self.month_edit.get_text()
+        day_value = self.day_edit.get_text()
+        hour_value = self.hour_edit.get_text()
+        minute_value = self.minute_edit.get_text()
+        logging.debug("year_value=%s", year_value)
+        logging.debug("month_value=%s", month_value)
+        logging.debug("day_value=%s", day_value)
+        logging.debug("hour_value=%s", hour_value)
+        logging.debug("minute_value=%s", minute_value)
+        had_err = False
+        if not self.year_edit.run_on_exit(): 
+            had_err = True
+        if not self.month_edit.run_on_exit(): 
+            had_err = True
+        if not self.day_edit.run_on_exit(): 
+            had_err = True
+        if not self.hour_edit.run_on_exit(): 
+            had_err = True
+        if not self.minute_edit.run_on_exit(): 
+            had_err = True
+        if had_err:
+            raise UIMessage, _("Invalid date/time. See errors above.")
+
+    def update_day_range(self, maxday=31):
+        '''
+        Update the day range displayed. The max number of days can vary
+        depending on the month, so calling functions can update appropriately.
+        
+        '''
+        self.center_win.add_text("(1-%d)" % maxday,
+                                 self.date_range_loc[0],
+                                 self.date_range_loc[1],
+                                 self.win_size_x - 3)
+        self.saved_days_in_month = maxday
+
+
+    def on_change_screen(self):
+        '''Save current user input for return to screen'''
+        self.saved_year = self.year_edit.get_text()
+        self.saved_month = self.month_edit.get_text()
+        self.saved_day = self.day_edit.get_text()
+        self.saved_hour = self.hour_edit.get_text()
+        self.saved_minute = self.minute_edit.get_text()
+
+    def on_continue(self):
+        '''Save time offset to profile'''
+        saved_time = datetime.datetime(int(self.year_edit.get_text()),
+                                       int(self.month_edit.get_text()),
+                                       int(self.day_edit.get_text()),
+                                       int(self.hour_edit.get_text()),
+                                       int(self.minute_edit.get_text()))
+        userdelta = saved_time - datetime.datetime.now()
+        logging.debug("delta time=%s", userdelta)
+        self.install_profile.system.time_offset = userdelta
+        install_datetime = datetime.datetime.now() + userdelta
+        logging.debug("date command would be: /usr/bin/date %s",
+                      install_datetime.strftime("%m%d%H%M%y"))
+
+def get_days_in_month(month_edit, year_edit, date_time):
+    '''
+    Get the number of days in the month. Assumes non-None
+    month and year field. Returns 31 if month field not valid
+    and 28 if Feb, but year not valid.
+    '''
+    if not date_time.month_is_valid:
+        logging.debug("get_days_in_month returning 31")
+        return(31)
+    
+    # if month set to Feb, check for leap year
+    month_str = month_edit.get_text()
+    if (int(month_str) == 2):
+        if not date_time.year_is_valid:
+            logging.debug("get_days_in_month returning 28")
+            return(28)
+        else:
+            cur_year =  year_edit.get_text()
+            logging.debug("cur_year %s", cur_year)
+            if len(cur_year) == 4:
+                return (calendar.monthrange(int(cur_year), 2)[1])
+
+    now = datetime.datetime.now()
+    return (calendar.monthrange(now.year, int(month_str))[1])
+
+
+def check_day_range(month_edit, day_edit, year_edit, date_time):
+    '''
+    Update the day range max with number of days in month. If days in 
+    day_edit field is greater than number of days in month, modify value
+    in day_edit field to number days in month.
+    '''
+    logging.debug('checking day range')
+    days_in_month = get_days_in_month(month_edit, year_edit, date_time)
+    logging.debug('%s days in month', days_in_month)
+    date_time.update_day_range(days_in_month)
+    
+    if not day_edit.get_text():
+        return
+    cur_day = int(day_edit.get_text())
+    if cur_day > days_in_month:
+        day_edit.textbox.do_command(EditField.CMD_MV_BOL) 
+        day_edit.set_text(str(days_in_month))
+        logging.debug('updating day to %s', days_in_month )
+
+
+def year_valid(year_edit, month_edit=None, day_edit=None,
+               date_time=None):
+    '''Check validity of year as each char entered'''
+    if date_time:
+        date_time.year_is_valid = False
+    year_str = year_edit.get_text()
+    if not year_str:
+        return True
+    now = datetime.datetime.now()
+    logging.log(LOG_LEVEL_INPUT, "validating year, text=%s=", year_str)
+    if not year_str.isdigit():
+        raise UIMessage, _("Year must be numeric")
+    if year_str[0] != now.strftime("%Y")[0]:
+        logging.debug("year doesn't start with 2, text=%s", year_str)
+        raise UIMessage, _("Year out of range")
+    if len(year_str) > 1 and year_str[1] != now.strftime("%Y")[1]:
+        logging.debug("year out of range=%s", year_str)
+        raise UIMessage, _("Year out of range")
+    if date_time:
+        date_time.year_is_valid = True
+        if len(year_str) == 4:
+            check_day_range(month_edit, day_edit, year_edit, date_time)
+    return True
+
+
+def year_on_exit(year_edit):
+    '''Check year when exiting field'''
+    year_str = year_edit.get_text()
+    logging.debug("year_on_exit, =%s=", year_str)
+    year_valid(year_edit)
+    if (len(year_str) != 4):
+        logging.debug("on exit year out of range=%s", input)
+        raise UIMessage, _("Year out of range")
+    return True
+
+
+def month_valid(month_edit, day_edit=None, year_edit=None, date_time=None):
+    '''Check validity of month as each char entered'''
+    if date_time:
+        date_time.month_is_valid = False
+    month_str = month_edit.get_text()
+    logging.log(LOG_LEVEL_INPUT, "validating month, text=%s=", month_str)
+    if not month_str:
+        return True
+    if not month_str.isdigit():
+        raise UIMessage, _("Month must be numeric")
+    logging.debug("len = %s, text=%s ", len(month_str), month_str)
+    if len(month_str) == 2:
+        if (int(month_str) > 12 or int(month_str) == 0):
+            logging.log(LOG_LEVEL_INPUT, "month out of range, =%s", month_str)
+            raise UIMessage, _("Month out of range")
+    if date_time:
+        date_time.month_is_valid = True
+        if int(month_str) > 0:
+            check_day_range(month_edit, day_edit, year_edit, date_time)
+    return True
+
+
+def month_on_exit(month_edit):
+    '''Check month when exiting field'''
+    month_str = month_edit.get_text() 
+    logging.debug("month_on_exit, =%s=", month_str)
+    month_valid(month_edit)
+    if (len(month_str) == 0 or int(month_str) == 0):
+        logging.debug("on exit month out of range=%s", month_str)
+        raise UIMessage, _("Month out of range")
+    return True
+
+
+def day_valid(day_edit, month_edit=None, year_edit=None, date_time=None):
+    '''Check validity of day as each char entered'''
+    day_str = day_edit.get_text()
+    logging.log(LOG_LEVEL_INPUT, "validating day, text=%s=", day_str)
+    if not day_str:
+        return True
+    if not day_str.isdigit():
+        raise UIMessage, _("Day must be numeric")
+    logging.log(LOG_LEVEL_INPUT, "len = %s, text=%s ", len(day_str), day_str)
+    
+    # When screen first comes up, there is no month/year_edit
+    if (month_edit is None or year_edit is None):
+        return True
+    
+    days_in_month = get_days_in_month(month_edit, year_edit, date_time)
+    if (len(day_str) == 2):
+        if (int(day_str) > days_in_month or int(day_str) == 0):
+            logging.debug("day out of range, =%s", day_str)
+            raise UIMessage, _("Day out of range")
+    return True
+
+
+def day_on_exit(day_edit):
+    '''Check day when exiting field'''
+    day_str = day_edit.get_text()
+    logging.debug("day_on_exit, =%s=", day_str)
+    day_valid(day_edit)
+    if (len(day_str) == 0 or int(day_str) == 0):
+        logging.debug("on exit day out of range=%s", day_str)
+        raise UIMessage, _("Day out of range")
+    return True
+
+
+def hour_valid(hour_edit): 
+    '''Check validity of hour as each char entered'''
+    hour_str = hour_edit.get_text()
+    logging.log(LOG_LEVEL_INPUT, "validating hour, text=%s=", hour_str)
+    if hour_str and not hour_str.isdigit():
+        raise UIMessage, _("Hour must be numeric")
+    if len(hour_str) == 2 and (int(hour_str) > 23):
+        logging.debug("hour out of range, =%s", hour_str)
+        raise UIMessage, _("Hour out of range")
+    return True
+
+
+def hour_on_exit(hour_edit):
+    '''Check hour when exiting field'''
+    hour_str = hour_edit.get_text()
+    logging.debug("hour_on_exit, =%s=", hour_str)
+    if not hour_str:
+        raise UIMessage, _("Hour out of range")
+    hour_valid(hour_edit)
+    return True
+
+
+def minute_valid(minute_edit):
+    '''Check validity of minute as each char entered'''
+    minute_str = minute_edit.get_text()
+    logging.log(LOG_LEVEL_INPUT, "validating minute, text=%s=", minute_str)
+    if minute_str and not minute_str.isdigit():
+        raise UIMessage, _("Minute must be numeric")
+    if len(minute_str) == 2 and (int(minute_str) > 59):
+        raise UIMessage, _("Minute out of range")
+    return True
+
+
+def minute_on_exit(minute_edit):
+    '''Check minute when exiting field'''
+    minute_str = minute_edit.get_text()
+    logging.debug("minute_on_exit, =%s=", minute_str)
+    if not minute_str:
+        raise UIMessage, _("Minute out of range")
+    minute_valid(minute_edit)
+    return True
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/disk_selection.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,388 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+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.text_install import _
+from osol_install.text_install.base_screen import BaseScreen, \
+                                                  QuitException, \
+                                                  UIMessage
+from osol_install.text_install.disk_window import DiskWindow, \
+                                                  get_minimum_size, \
+                                                  get_recommended_size
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.scroll_window import ScrollWindow
+from osol_install.text_install.window_area import WindowArea
+from osol_install.text_install.ti_install_utils import get_zpool_list
+import osol_install.tgt as tgt
+
+
+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 OpenSolaris be installed?")
+    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 = _("OpenSolaris cannot be installed on any disk")
+    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")
+    
+    def __init__(self, main_win):
+        super(DiskScreen, self).__init__(main_win)
+        self.recommended_size = get_recommended_size().size_as("gb")
+        self.minimum_size = get_minimum_size().size_as("gb")
+        size_dict = {"recommend" : self.recommended_size,
+                     "min" : self.minimum_size}
+        self.size_line = DiskScreen.SIZE_TEXT % size_dict
+        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 = header[1][:header[0]-1]
+            header_str = header_str.ljust(header[0]-1)
+            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
+    
+    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 = len(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
+        
+        '''
+        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,
+                                     len(self.disk_header_text))
+        
+        y_loc += 1
+        disk_win_area = WindowArea(4, len(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 = type_field.ljust(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 = device_field.ljust(len_dev)
+            disk_text_fields.append(device_field)
+            if disk.vendor is not None:
+                mftr_field = disk.vendor[:len_mftr]
+                mftr_field = mftr_field.ljust(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)
+        try:
+            self.disk_win.activate_object(self.install_profile.disk.TUI_INDEX)
+        except AttributeError:
+            self.disk_win.activate_object()
+    
+    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.num_targets > 0:
+            disk = self.disk_detail.disk_info
+            self.install_profile.disk = deepcopy(disk)
+            self.install_profile.original_disk = disk
+            self.install_profile.disk.TUI_INDEX = 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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/disk_window.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,811 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+'''
+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 _, LOG_LEVEL_INPUT
+from osol_install.text_install.base_screen import UIMessage
+from osol_install.text_install.edit_field import EditField
+from osol_install.text_install.inner_window import InnerWindow, no_action
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.scroll_window import ScrollWindow
+from osol_install.text_install.window_area import WindowArea
+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
+
+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
+        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.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
+            left_header_str = left_header_str[:header[0]-1]
+            right_header_str = right_header_str[:header[0]-1]
+            # Pad with extra space(s) to align the columns
+            left_header_str = left_header_str.ljust(header[0]-1)
+            right_header_str = right_header_str.ljust(header[0]-1)
+            self.left_header_string.append(left_header_str)
+            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,
+                          len(self.left_header_string))
+        self.window.hline(1, right_win_offset, curses.ACS_HLINE,
+                          len(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_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_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)
+        if part_info.editable(self.disk_info):
+            part_field.objects = [edit_field]
+            if ((part_field is not self.ext_part_field) or
+                (self.get_active_object() is self.left_win)): 
+                part_field.activate_object(edit_field)
+        else:
+            edit_field.make_inactive()
+            part_field.objects = []
+            part_field.active_object = None
+        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 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:
+            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)
+        else:
+            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=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=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)
+            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 +
+                                  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):
+        '''Refresh self, left win and right win explicitly'''
+        super(DiskWindow, self).no_ut_refresh()
+        self.left_win.no_ut_refresh()
+        self.right_win.no_ut_refresh()
+    
+    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_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_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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/edit_field.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,412 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Support for building and utilizing an editable text field
+'''
+
+import logging
+import curses
+from curses.textpad import Textbox
+from curses.ascii import isprint, ctrl, ismeta
+
+from osol_install.text_install.base_screen import UIMessage
+from osol_install.text_install.inner_window import InnerWindow, consume_action
+
+
+class RefreshRedirect(object):
+    '''
+    Class for redirecting calls to window.refresh()
+    
+    curses.textpad assumes that the window is a 'window', not a 'pad'.
+    window.refresh() takes no arguments, but pad.refresh(...) takes 6
+    arguments. Additionally, the curses.textpad doesn't move the cursor
+    properly for pad objects after calls to window.addch() and window.move().
+    This class contains a reference to an EditField and a curses window or pad,
+    and redirects calls to refresh, addch, and move. RefreshRedirect's
+    implementations of those functions provide the interface that
+    curses.textpad expects in the context of the Text Installer UI
+    framework.
+    
+    '''
+    def __init__(self, edit_field, curses_win):
+        self._edit_field = edit_field
+        self._curses_win = curses_win
+    
+    def __getattribute__(self, name):
+        '''Redirect attribute access in some cases'''
+        if name == "refresh":
+            return object.__getattribute__(self, "_edit_field").refresh
+        elif name == "addch":
+            return object.__getattribute__(self, "_addch")
+        elif name == "move":
+            return object.__getattribute__(self, "_move")
+        elif name == "_curses_win":
+            return object.__getattribute__(self, "_curses_win")
+        else:
+            return getattr(object.__getattribute__(self, "_curses_win"), name)
+    
+    def _addch(self, *args):
+        '''Sync the cursor properly after call to addch'''
+        self._curses_win.addch(*args)
+        self._curses_win.cursyncup()
+    
+    def _move(self, *args):
+        '''Sync the cursor properly after call to move'''
+        self._curses_win.move(*args)
+        self._curses_win.cursyncup()
+
+
+class EditField(InnerWindow):
+    '''EditFields represent editable text areas on the screen
+    
+    At any time, the text of the object can be accessed by
+    referencing an EditField's 'text' parameter (edit_field.text).
+    Note that this returns a list of character codes. To get a string,
+    see EditField.get_text()
+    
+    '''
+    
+    ASTERISK_CHAR = ord('*')
+    
+    CMD_DONE_EDIT = ord(ctrl('g'))
+    CMD_MV_BOL = ord(ctrl('a')) # Move to beginning of line
+    CMD_MV_EOL = ord(ctrl('e')) # Move to end of line
+    CMD_CLR_LINE = ord(ctrl('k'))
+    
+    def __init__(self, area, window=None, text="", masked=False,
+                 color_theme=None, color=None, highlight_color=None,
+                 validate=None, on_exit=None, error_win=None,
+                 numeric_pad=None, **kwargs):
+        '''See InnerWindow.__init__
+        
+        In general, specifying a specific color_theme is unnecessary, unless
+        this instance requires a theme other than that of the rest of the
+        program 
+        
+        window (required): A parent InnerWindow
+        
+        area (required): Describes the area within the parent window to be used.
+                         area.lines must be 1, as only single line EditFields
+                         are currently supported.
+        
+        text (optional): The text in this field, before it is edited by
+        the user. Defaults to empty string.
+        
+        masked (optional): If True, then this field will display bullets when
+        the user types into it, instead of echo'ing the text
+        
+        color_theme (optional): The color_theme for this edit field. By default
+        the parent window's theme is used. color_theme.edit_field is used
+        as the background color; color_theme.highlight_edit is the background
+        when this EditField is active.
+        
+        validate (optional) - A function for validation on each keystroke.
+        The function passed in should take as parameter a string, and if
+        invalid, it should raise a UIMessage with an indicator of why. This
+        function, if present, will be called after each keystroke.
+        IMPORTANT: If no UIMessage is raised, the string is assumed to be
+        valid
+        
+        Additional keyword arguments can be passed to this function by
+        modifying this EditField's validate_kwargs dictionary
+        
+        on_exit (optional) - A function for final validation. This is called
+        when this EditField loses focus. Like validate, it should accept a
+        string argument and raise a UIMessage if the string is not valid.
+        
+        Additional keyword arguments can be passed to this function by
+        modifying this EditField's on_exit_kwargs dictionary
+        
+        error_win (optional) - If given, error_win.display_error() is called
+        whenever validate or on_exit raise a UIMessage (the UIMessage's
+        explanation string is passed as parameter). Additionally,
+        error_win.clear_err() is called when those functions return
+        successfully.
+        
+        numeric_pad (optional) - A single character to pad self.text with.
+        If given, when this EditField handles input, it works in numeric mode.
+        In numeric mode:
+            * When editing begins, numeric_pad is stripped from the current
+              text in the field. Text is shifted to the left to compensate
+            * When done editing, the text is right justified, and padded with
+              the value of numeric_pad. In general, either a space or zero will
+              be used as the value of numeric_pad
+            * IMPORTANT: The function hooks for 'validate' and 'on_exit' are
+              called using the value of self.get_text PRIOR to padding.
+        
+        '''
+        self.numeric_pad = numeric_pad
+        self.right_justify = False
+        self.on_exit_kwargs = {}
+        self.validate_kwargs = {}
+        self.validate = validate
+        self.on_exit = on_exit
+        self.error_win = error_win
+        if color_theme is None:
+            color_theme = window.color_theme
+        if color is None:
+            color = color_theme.edit_field
+        if highlight_color is None:
+            highlight_color = color_theme.highlight_edit
+        
+        if area.lines != 1:
+            raise ValueError("area.lines must be 1")
+        super(EditField, self).__init__(area, window, color_theme, color,
+                                        highlight_color, **kwargs)
+        self.masked = masked
+        self.masked_char = EditField.ASTERISK_CHAR
+        self.textbox = Textbox(RefreshRedirect(window, self.window))
+        self.textbox.stripspaces = True
+        self.input_key = None
+        self.text = None
+        self.key_dict[curses.KEY_ENTER] = consume_action
+        self.set_text(text)
+        self.clear_on_enter = False
+    
+    def set_text(self, text):
+        '''Set the text of this EditField to text. Processes each
+        character individually; thus emulating a user typing in the text.
+        This means that each substring of text that start at text[0] must
+        be valid in the context of any validation function this EditField
+        has.
+        
+        If numeric_pad is set, pad text with it if field isn't blank.
+        '''
+        if self.numeric_pad is not None:
+            width = self.area.columns - 1
+            if text:
+                text = text.lstrip(self.numeric_pad)
+                text = text.rjust(width, self.numeric_pad)
+        self._set_text(text)
+    
+    def _set_text(self, text):
+        '''Used internally to bypass the the public
+        interface's numeric_pad functionality'''
+        if text is None:
+            text = u""
+        self.clear_text()
+        for char in text:
+            if self.masked:
+                self.textbox.do_command(self.masked_char)
+            else:
+                self.textbox.do_command(ord(char))
+            self.text.append(char)
+        self.no_ut_refresh()
+    
+    def handle_input(self, input_key):
+        '''
+        For each keystroke, determine if it's a special character (and needs
+        to end editing), printable character, or backspace.
+        
+        For special characters, send the return the done-editing code (CTRL-G),
+        and store the special character for processing by parent window
+        objects.
+        
+        If printable, append it to self.text, and try to validate. If
+        validation fails, reject the character.
+        
+        '''
+        input_key = self.translate_input(input_key)
+        if self.is_special_char(input_key):
+            logging.debug("Got special key, breaking")
+            self.input_key = input_key
+            return EditField.CMD_DONE_EDIT
+        else:
+            self.input_key = None
+        if isprint(input_key) or (ismeta(input_key) and
+                                  input_key < curses.KEY_MIN):
+            # isprint: ASCII characters
+            # ismeta and < curses.KEY_MIN: Remaining UTF-8 characters
+            # > curses.KEY_MIN: Special key such as down arrow, backspace, etc.
+            self.text.append(unichr(input_key))
+            if not self.is_valid():
+                if len(self.text) > 0:
+                    self.text.pop()
+                return None
+            if self.masked:
+                input_key = self.masked_char
+        elif input_key == curses.KEY_BACKSPACE:
+            if len(self.text) > 0:
+                self.text.pop()
+            self.is_valid()
+            # Run self.is_valid here so that any functional side effects can
+            # occur, but don't check the return value (removing a character
+            # from a valid string should never be invalid, and even if it were,
+            # it would not make sense to add the deleted character back in)
+        
+        return input_key
+    
+    def right_justify_loop(self):
+        '''Loop for handling the special case of a right justified field.
+        Called by EditField.process().
+        
+        To right justify the editable field, the entire field needs
+        to be redrawn after each keystroke.
+        
+        '''
+        input_key = None
+        while input_key != EditField.CMD_DONE_EDIT:
+            input_key = self.handle_input(self.getch())
+            self.set_text(self.get_text())
+            curses.doupdate()
+    
+    def process(self, input_key):
+        '''Process a keystroke. For an EditField, this means preparing the
+        textpad for processing and passing the input_key in.
+        
+        Try to enable the blinking cursor (if it was disabled) before
+        editing begins, so the user can see where they're typing. Once
+        finished, restore the cursor state to its previous condition.
+        
+        After editing, return self.input_key, which will either be None
+        (indicating all keystrokes were processed by the Textbox) or
+        a special character (such as F2) which caused EditField.handle_input
+        to stop processing text through the Textbox.
+        
+        '''
+        try:
+            curses.curs_set(2)
+        except curses.error:
+            logging.debug("Got curses.error when enabling cursor")
+        
+        if input_key is not None and not self.is_special_char(input_key):
+            # Put input_key back on stack so that textbox.edit can read it
+            curses.ungetch(input_key)
+            if self.numeric_pad is not None:
+                self._set_text(self.get_text().lstrip(self.numeric_pad))
+            
+            if self.clear_on_enter:
+                self.clear_text()
+            else:
+                # Move to end of previous input.
+                self.textbox.do_command(EditField.CMD_MV_EOL)
+            if self.right_justify:
+                self.right_justify_loop()
+            else:
+                self.textbox.edit(self.handle_input)
+            return_key = self.input_key
+            if self.numeric_pad is not None:
+                self.set_text(self.get_text())
+        else:
+            return_key = input_key
+        logging.debug("Returning: %s", return_key)
+        return return_key
+    
+    def get_text(self):
+        '''Join the array of characters as a unicode string'''
+        return u"".join(self.text)
+    
+    def is_special_char(self, input_key):
+        '''Check to see if this is a keystroke that should break us out of
+        adding input to the Textbox and return control to the parent window
+        
+        '''
+        if (input_key in range(curses.KEY_F0, curses.KEY_F10) or
+            input_key in self.key_dict):
+            return True
+        else:
+            return False
+    
+    def is_valid(self):
+        '''Check to see if the text we have is valid or not.
+        First check the length to make sure it fits in the space alloted.
+        Then, if this EditField has a validate function, call it (passing
+        in any validate_kwargs we have).
+        
+        If validate raises an exception, display the error (if we have a
+        handle to an ErrorWindow) and return False.
+        
+        '''
+        win_size_x = self.window.getmaxyx()[1]
+        if len(self.get_text().lstrip(self.numeric_pad)) >= win_size_x:
+            return False
+        elif callable(self.validate):
+            try:
+                self.validate(self, **self.validate_kwargs)
+                if self.error_win is not None and self.error_win.visible:
+                    self.error_win.clear_err()
+                return True
+            except UIMessage as error_str:
+                if self.error_win is not None:
+                    self.error_win.display_err(str(error_str))
+                return False
+        return True
+    
+    def run_on_exit(self):
+        '''Fire the on_exit function, if there is one. If an error occurs,
+        and this EditField has an error_win, display it there.
+        
+        '''
+        if callable(self.on_exit):
+            try:
+                self.on_exit(self, **self.on_exit_kwargs)
+                if self.error_win is not None and self.error_win.visible:
+                    self.error_win.clear_err()
+                return True
+            except UIMessage as error_str:
+                if self.error_win is not None:
+                    self.error_win.display_err(str(error_str))
+                return False
+        return True
+    
+    def make_active(self):
+        '''Enable the cursor when activating this field'''
+        super(EditField, self).make_active()
+        try:
+            curses.curs_set(2)
+        except curses.error:
+            logging.debug("Got curses.error when enabling cursor")
+    
+    def make_inactive(self):
+        '''Fire the on_exit function before leaving the field and making
+        it inactive.
+        
+        '''
+        self.run_on_exit()
+        try:
+            curses.curs_set(0)
+        except curses.error:
+            logging.debug("Got curses.error when reverting cursor")
+        super(EditField, self).make_inactive()
+    
+    def clear_text(self):
+        '''Issue the commands to textbox to clear itself, and reset self.text
+        to an empty array.
+        
+        '''
+        # Move cursor to left side of window
+        self.textbox.do_command(EditField.CMD_MV_BOL)
+        # Clear from cursor to end of line
+        self.textbox.do_command(EditField.CMD_CLR_LINE)
+        self.text = []
+        self.no_ut_refresh()
+    
+    def get_cursor_loc(self):
+        '''Cursor should be positioned at the end of the entered text'''
+        win_loc = self.window.getbegyx()
+        x_loc = win_loc[1]
+        if not self.clear_on_enter:
+            x_loc += len(self.text)
+        return (win_loc[0], x_loc)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/error_window.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,111 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+UI Component for displaying error messages
+'''
+
+import curses
+import logging
+
+from osol_install.text_install.inner_window import InnerWindow
+
+
+class ErrorWindow(InnerWindow):
+    '''Simple subclass of InnerWindow for displaying and hiding errors
+    
+    This window is only intended for use with text content (adding subwindows
+    to this class is undefined)
+    
+    '''
+    
+    FLASH_TIME = 250
+    
+    def __init__(self, area, window=None, color_theme=None, color=None,
+                 highlight_color=None, centered=True, **kwargs):
+        '''
+        See InnerWindow.__init__
+        
+        color - defaults to color_theme.default
+        highlight_color - defaults to color_theme.error_msg
+        '''
+        self.visible = False
+        if color_theme is None:
+            color_theme = window.color_theme
+        if color is None:
+            color = color_theme.default
+        if highlight_color is None:
+            highlight_color = color_theme.error_msg
+        self.centered = centered
+        super(ErrorWindow, self).__init__(area, window, color_theme, color,
+                                          highlight_color, add_obj=False,
+                                          **kwargs)
+        self.window.timeout(ErrorWindow.FLASH_TIME)
+    
+    def display_err(self, text):
+        '''Display error 'text'. Will also flash
+        the error text if this box was already visible, to draw
+        the user's attention to the new (or existing) error
+        
+        Restores cursor location after updating
+        
+        '''
+        cursor_loc = curses.getsyx()
+        self.clear()
+        logging.debug("displaying err '%s'", text)
+        self.add_text(text, centered=self.centered)
+        self.make_active()
+        curses.setsyx(cursor_loc[0], cursor_loc[1])
+        curses.doupdate()
+        if self.visible:
+            self.flash()
+        self.visible = True
+    
+    def clear_err(self):
+        '''Clear error text and mark this window inactive
+        
+        Restores cursor location after updating
+        '''
+        if self.visible:
+            cursor_loc = curses.getsyx()
+            self.clear()
+            self.make_inactive()
+            curses.setsyx(cursor_loc[0], cursor_loc[1])
+            curses.doupdate()
+            self.visible = False
+    
+    def flash(self):
+        '''Flash this error window'''
+        if self.visible:
+            cursor_loc = curses.getsyx()
+            flash_color = self.highlight_color ^ curses.A_REVERSE
+            self.set_color(flash_color)
+            curses.setsyx(cursor_loc[0], cursor_loc[1])
+            curses.doupdate()
+            gotch = self.window.getch()
+            if gotch != -1:
+                curses.ungetch(gotch)
+            self.set_color(self.highlight_color)
+            curses.setsyx(cursor_loc[0], cursor_loc[1])
+            curses.doupdate()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/fdisk_partitions.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,203 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Screen for selecting to use whole disk, or a partition/slice on the disk
+'''
+
+import logging
+import platform
+
+from osol_install.text_install.base_screen import BaseScreen, SkipException
+from osol_install.text_install.disk_window import DiskWindow
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.window_area import WindowArea
+from osol_install.text_install import _
+
+
+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 = _("OpenSolaris can be installed on the whole "
+                        "disk or a partition on the disk.")
+    PARAGRAPH_PART_SLICE = _("OpenSolaris can be installed in the "
+                             "whole fdisk partition or within a "
+                             "slice in the partition")
+    PARAGRAPH_SLICE = _("OpenSolaris can be installed on the whole"
+                        " disk or a slice on the disk.")
+    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")
+    
+    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
+        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
+        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
+        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.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
+        
+        '''
+        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
+            logging.debug("Preserved partition with existing slices:"
+                          " presenting option to install into a slice")
+        else:
+            self.disk_info = self.install_profile.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, self.disk_info,
+                                   window=self.center_win)
+        y_loc += disk_win_area.lines
+        
+        y_loc += 3
+        whole_disk_width = len(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 = len(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))
+            self.disk_info.use_whole_segment = False
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/help_screen.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,320 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Display individual help screen or help topics screen 
+'''
+
+import curses
+import locale
+import logging
+import os
+import platform
+
+from osol_install.text_install import _
+from osol_install.text_install.action import Action
+from osol_install.text_install.base_screen import BaseScreen
+from osol_install.text_install.inner_window import InnerWindow
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.scroll_window import ScrollWindow
+from osol_install.text_install.window_area import WindowArea
+
+
+HELP_PATH = "/usr/share/text-install/help/"
+
+
+class HelpScreen(BaseScreen):
+    '''Show localized help file pertaining to last traversed screen or
+    help topics list from which to choose a desired help topic.
+    
+    '''
+    
+    HELP_HEADER = _("Help Topics")
+    HELP_INDEX = _("Help Index")
+    INTRO = _("Select a topic and press Continue.")
+    
+    def __init__(self, main_win):
+        super(HelpScreen, self).__init__(main_win)
+        
+        self.locale = locale.setlocale(locale.LC_MESSAGES, "")
+        logging.debug("locale=%s", self.locale)
+        
+        self.screen = None
+        self.screen_last = None
+        self.help_info = []
+        self.help_dict = None
+        self.topics = False
+        self.scroll_region = None
+        self.cur_help_idx = 0
+        self.is_x86 = (platform.processor() == "i386") 
+        self.setup_help_data()
+    
+    def setup_help_data(self):
+        '''Setup the help_dict and help_info structures
+        
+        help_dict contains:
+            key: screen name 
+            tuple:  (<helpfile_name>, <header for help screen>)
+            tuple:  (<helpfile_name>, <header for help screen
+                                       and help topics menu entry>)
+        
+        '''
+        
+        self.help_dict = \
+            {
+            "WelcomeScreen": ("welcome.txt",
+                              _("Welcome and Navigation Instructions")),
+            "DiskScreen": ("disks.txt", _("Disks")),
+            "NetworkTypeScreen": ("network.txt", _("Network")),
+            "NICSelect": ("network_manual.txt",
+                          _("Manual Network Configuration")),
+            "NICConfigure": ("network_manual.txt",
+                             _("Manually Configure: NIC")),
+            "TimeZone": ("timezone.txt", _("Time Zone")),
+            "DateTimeScreen": ("date_time.txt", _("Date and Time")),
+            "UserScreen": ("users.txt", _("Users")),
+            "SummaryScreen": ("summary.txt", _("Installation Summary"))
+            }
+        
+        # add x86 and SPARC specific help_dict entries
+        if self.is_x86:
+            self.help_dict["FDiskPart"] =  \
+                ("x86_fdisk_partitions.txt", _("Fdisk Partitions"))
+            self.help_dict["PartEditScreen"] = \
+                ("x86_fdisk_partitions_select.txt", _("Select Partition"))
+            self.help_dict["FDiskPart.slice"] = \
+                ("x86_fdisk_slices.txt", _("Solaris Partition Slices"))
+            self.help_dict["PartEditScreen.slice"] = \
+                ("x86_fdisk_slices_select.txt", _("Select Slice"))
+        else:
+            self.help_dict["FDiskPart"] = \
+                ("sparc_solaris_slices.txt", _("Solaris Slices"))
+            self.help_dict["PartEditScreen"] = \
+                ("sparc_solaris_slices_select.txt", _("Select Slice"))
+        
+        logging.debug("self.help_dict=%s", self.help_dict)
+        
+        # help_info contains tuples:
+        #    (tuple of screen names, format of text) 
+        
+        self.help_info = []
+        self.help_info.append((("WelcomeScreen",), "%s"))
+        self.help_info.append((("DiskScreen",), "%s"))
+        
+        # add x86 and SPARC specific entries to self.help_info
+        if self.is_x86: 
+            self.help_info.append((("FDiskPart",), "  %s"))
+            self.help_info.append((("PartEditScreen",), "    %s"))
+            self.help_info.append((("FDiskPart.slice",), "    %s"))
+            self.help_info.append((("PartEditScreen.slice",), "    %s"))
+        else:
+            self.help_info.append((("FDiskPart",), "  %s"))
+            self.help_info.append((("PartEditScreen",), "  %s"))
+        self.help_info.append((("NetworkTypeScreen",), "%s"))
+        self.help_info.append((("NICSelect",), "  %s"))
+        self.help_info.append((("NICConfigure",), "  %s"))
+        self.help_info.append((("TimeZone",), "%s"))
+        self.help_info.append((("DateTimeScreen",), "%s"))
+        self.help_info.append((("UserScreen",), "%s"))
+        self.help_info.append((("SummaryScreen",), "%s"))
+        
+        logging.debug("self.help_info=%s", self.help_info)
+    
+    def set_actions(self):
+        '''Remove the continue key for help screen and Help key for
+        help topics screen. Redirect F2_Continue to display the selected
+        topic, when at the topics list
+        
+        '''
+        
+        logging.debug("in set_actions self.class_name=%s",
+                      self.__class__.__name__)
+        
+        # change F6 description
+        self.main_win.help_action.text = HelpScreen.HELP_INDEX
+        
+        # change continue to call continue_action, rather than
+        # normal continue. Though we stay on the same screen,
+        # we simulate the continue here by changing the screen text.
+        #
+        help_continue = Action(curses.KEY_F2, _("Continue"),
+                               self.continue_action)
+        self.main_win.actions[help_continue.key] = help_continue
+        
+        if (self.screen == self.__class__.__name__):
+            # help topics screen
+            self.main_win.actions.pop(self.main_win.help_action.key, None)
+        else:
+            # help screen
+            self.main_win.actions.pop(self.main_win.continue_action.key, None)
+
+    def display_help_topics(self):
+        '''Display the help topics screen.'''
+        
+        self.main_win.set_header_text(HelpScreen.HELP_HEADER)
+        y_loc = 1
+        
+        y_loc += self.center_win.add_paragraph(HelpScreen.INTRO, y_loc, 1,
+                                               max_x=(self.win_size_x - 1))
+        y_loc += 1
+        
+        area = WindowArea(scrollable_lines=(len(self.help_info)+1),
+                          y_loc=y_loc, x_loc=0)
+        logging.debug("lines=%s", len(self.help_dict))
+        area.lines = self.win_size_y - (y_loc + 1)
+        area.columns = self.win_size_x
+        
+        self.scroll_region = ScrollWindow(area, window=self.center_win)
+        
+        # add the entries to the screen
+        logging.debug("range=%s", len(self.help_info))
+        for idx, info in enumerate(self.help_info):
+            # create ListItem for each help topic
+            topic_format = info[1]
+            help_topic = self.get_help_topic(info[0])
+            help_topic = topic_format % help_topic
+            hilite = min(self.win_size_x, len(help_topic) + 1)
+            list_item = ListItem(WindowArea(1, hilite, idx, 0),
+                                 window=self.scroll_region, text=help_topic)
+            help_screens = info[0]
+            logging.debug("help_screens=%s", list(help_screens))
+            logging.debug("self.screen_last=%s", self.screen_last)
+            if self.screen_last in help_screens:
+                logging.debug("Set cur_help_idx = %s", idx)
+                self.cur_help_idx = idx
+        logging.debug("beg_y=%d, beg_x=%d", *list_item.window.getbegyx())
+        
+        self.center_win.activate_object(self.scroll_region)
+        self.scroll_region.activate_object(self.cur_help_idx)
+    
+    def continue_action(self, dummy=None):
+        '''Called when user preses F2 on help topics screen.
+        Results in show being called again to display single file help
+        of chosen topic.
+         
+        '''
+        logging.debug("continue_action:%s", self.scroll_region.active_object)
+        cur_topic = self.scroll_region.active_object
+        self.screen = self.help_info[cur_topic][0][0]
+        logging.debug("continue_action self.screen=%s", self.screen)
+        self.topics = False
+        return self
+    
+    def get_help_topic(self, name_classes=None):
+        '''Get the help topic from the dictionary, given the help class
+        tuple passed in. The single file help header in help_dict is
+        also the entry used in the help topics menu.
+        
+        '''
+        for key in self.help_dict.keys():
+            if key in name_classes:
+                return self.help_dict[key][1]
+        return ""
+    
+    def display_help(self):
+        '''Display the single file help screen'''
+        # customize header
+        help_header = "%s: %s"
+        logging.debug("self.screen is =%s", self.screen)
+        if self.screen in self.help_dict:
+            help_header = help_header % (_("Help"),
+                                         self.help_dict[self.screen][1])
+            help_text = self.get_help_text(self.help_dict[self.screen][0])
+        else:
+            help_header = help_header % (_("Help"), _("Not Available"))
+            help_text = _("Help for this screen is not available")
+        
+        self.main_win.set_header_text(help_header)
+        
+        help_text = InnerWindow.convert_paragraph(help_text,
+                                                  self.win_size_x - 5)
+        logging.debug("help_text #lines=%d, text is \n%s",
+                      len(help_text), help_text)
+        area = WindowArea(x_loc=0, y_loc=1,
+                          scrollable_lines=(len(help_text)+1))
+        area.lines = self.win_size_y - 1
+        area.columns = self.win_size_x
+        self.scroll_region = ScrollWindow(area, window=self.center_win)
+        self.scroll_region.add_paragraph(help_text, start_x=(area.x_loc + 3))
+        self.center_win.activate_object(self.scroll_region)
+    
+    def _show(self):
+        '''Display the screen, either the single file help or help topics.'''
+        
+        logging.debug("in show self.screen=%s", self.screen)
+        
+        if (self.screen is self.__class__.__name__):
+            logging.debug("setting self topics to true:")
+            self.topics = True
+        else:
+            self.topics = False
+            self.screen_last = self.screen
+            logging.debug("setting self.screen_last to %s", self.screen_last)
+        
+        if self.topics:
+            self.display_help_topics()
+        else:
+            self.display_help()
+    
+    def get_help_text(self, filename=None):
+        '''
+        Get the localized help text for the filename passed in.
+        First check locid directory. If not there, strip off 
+        dot extension (fr_FR.UTF-8 becomes fr_FR). If not there,
+        truncate to 2 chars (fr).  If not there, use C.
+        '''
+        if filename is None:
+            return ("")
+        
+        help_file = None
+        try:
+            locid = self.locale
+            path = "%s%s/%s"
+            full_path = path % (HELP_PATH, locid, filename)
+            logging.debug("Accessing help file %s", full_path)
+            if (not os.access(full_path, os.R_OK)): 
+                if (locid.find(".") > 0):
+                    locid = locid.split(".")[0]
+                    full_path = path % (HELP_PATH, locid, filename)
+                    logging.debug("Accessing help file %s", full_path)
+                    if (not os.access(full_path, os.R_OK)): 
+                        if (len(locid) > 1):
+                            locid = locid[:2]
+                            full_path = path % (HELP_PATH, locid, filename)
+                            logging.debug("Accessing help file %s", full_path)
+                            if (not os.access(full_path, os.R_OK)):
+                                locid = "C"
+                                full_path = path % (HELP_PATH, locid, filename)
+            logging.debug("Opening help file %s", full_path)
+            help_file = open(full_path, 'r')
+        except IOError:
+            logging.debug("Unable to open help file %s", full_path)
+            help_text = _("Help for this screen is not available")
+        else:
+            help_text = help_file.read()
+            logging.debug("Done reading help file %s", full_path)
+        if help_file:
+            help_file.close()
+        return help_text
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/inner_window.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,566 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Generic UI pieces representing a portion of the window. Provides
+support for handling input, writing text to the screen, and managing
+sub-windows within the window.
+'''
+
+
+import logging
+import curses
+from curses.ascii import ctrl
+from copy import copy
+
+from osol_install.text_install import LOG_LEVEL_INPUT
+
+
+KEY_ESC = 27
+KEY_BS = 127 # Backspace code that curses doesn't translate right
+KEY_CTRL_H = ord(ctrl('h'))
+KEY_TAB = ord(ctrl('i'))
+KEY_ENTER = ord(ctrl('j'))
+ZERO_CHAR = ord('0')
+
+
+def no_action(input_key):
+    '''Supports defining actions which have no effect and allow parent
+    windows to handle the key.
+    
+    '''
+    return input_key
+
+
+def consume_action(dummy):
+    '''Supports defining an action which has no effect, and consume the
+    keystroke so that parents do not handle it.
+    
+    '''
+    return None
+
+
+class InnerWindow(object):
+    '''Wrapper around curses.windows objects providing common functions
+    
+    An InnerWindow wraps around a curses window, and represents an area
+    of the screen. Each InnerWindow requires a parent window. The 'ultimate'
+    parent of all InnerWindows is the sole instance of MainWindow.
+    
+    By default, InnerWindows have functions for adding text, processing input,
+    and managing children InnerWindows.
+    
+    The following class variables are used to indicate the status of ESC key
+    navigations.
+    
+    BEGIN_ESC indicates that the next keystroke, if 0-9, should be
+    translated to F#
+    
+    USE_ESC indicates that, at some point during program execution,
+    ESC has been pressed, and the footer should, for the remainder of program
+    execution, print Esc-#_<description> for navigation descriptions. Once set
+    to True, it should never be set back to False.
+    
+    UPDATE_FOOTER is a flag that indicates that Esc was just hit for the
+    first time, and the managing window should immediately update the footer
+    text.
+    
+    '''
+    BEGIN_ESC = False
+    USE_ESC = False
+    UPDATE_FOOTER = False
+    KEY_TRANSLATE = {KEY_TAB : curses.KEY_DOWN,
+                     KEY_ENTER : curses.KEY_ENTER,
+                     KEY_BS : curses.KEY_BACKSPACE,
+                     KEY_CTRL_H : curses.KEY_BACKSPACE}
+    BKGD_CHAR = ord(' ')
+    REPAINT_KEY = ord(ctrl('L'))
+    
+    def no_ut_refresh(self):
+        '''Call noutrefresh on the curses window, and synchronize the
+        cursor location as needed
+        
+        '''
+        if self.is_pad: # Let the parent ScrollWindow handle pad updates
+            self.window.cursyncup()
+            self.pad.no_ut_refresh()
+        else:
+            self.window.noutrefresh()
+    
+    def refresh(self):
+        '''Like curses.refresh(), call no_ut_refresh followed by doupdate()'''
+        self.no_ut_refresh()
+        curses.doupdate()
+    
+    def redrawwin(self):
+        '''Mark the window and its children so that it will be completely
+        redrawn on the next call to do_update
+        
+        '''
+        self.window.redrawwin()
+        for win in self.more_windows:
+            win.redrawwin()
+        self.no_ut_refresh()
+        for obj in self.all_objects:
+            obj.redrawwin()
+    
+    def set_color(self, color):
+        '''Sets the color attributes to 'color'
+        
+        This private method immediately updates the background color.
+        Note that it doesn't reference self.color
+        
+        '''
+        if color is None:
+            return
+        
+        self.window.bkgd(InnerWindow.BKGD_CHAR, color)
+        self.no_ut_refresh()
+        
+        for win in self.more_windows:
+            win.bkgd(InnerWindow.BKGD_CHAR, color)
+            win.noutrefresh()
+    
+    def _adjust_area(self, window):
+        '''Create a copy of area, and adjust its coordinates to be absolute
+        if needed
+        
+        '''
+        if not self.is_pad:
+            if isinstance(window, InnerWindow):
+                self.area.relative_to_absolute(window.window,
+                                               border=window.border_size)
+            elif window is not None:
+                self.area.relative_to_absolute(window)
+    
+    def _init_win(self, parent):
+        '''Create the curses window'''
+        if self.is_pad:
+            logging.debug("lines=%d, columns=%d, y_loc=%d, x_loc=%d",
+                          self.area.lines, self.area.columns, self.area.y_loc,
+                           self.area.x_loc)
+            self.window = parent.window.subwin(self.area.lines,
+                                               self.area.columns,
+                                               self.area.y_loc,
+                                               self.area.x_loc)
+            self.pad = parent.pad
+        else:
+            self.window = curses.newwin(self.area.lines, self.area.columns,
+                                        self.area.y_loc, self.area.x_loc)
+        
+    
+    def __init__(self, area, window=None, color_theme=None, color=None,
+                 highlight_color=None, at_index=None, add_obj=True,
+                 border_size=(0, 0), data_obj=None):
+        '''Build an InnerWindow
+        
+        area (required): Describes the area to use when building this window.
+        Coordinates should be relative to window, if window is given. If window
+        is not given, these must be absolute coordinates on the terminal
+        
+        window (optional): The parent window. If given, area is assumed to
+        indicate a location within the parent. Additionally, if window is
+        an InnerWindow, window.add_object(self) is called to register this
+        new window with its parent
+        
+        color_theme (required if curses window): The color theme for this
+        window. This property gets propagated to subwindows. If None, the
+        parent window's color_theme is used. Unless this window requires
+        unique coloring, the parent theme should be used.
+        
+        color (optional): The color attributes for this window. If None,
+        color_theme.default is used. In general, this parameter is reserved
+        for subclasses of InnerWindow. Other consumers should pass in an
+        appropriate color_theme.
+        
+        highlight_color (optional): Color attributes for this window when
+        'selected' or 'highlighted.' Defaults to color (meaning
+        no highlighting is used. In general, this parameter is reserved
+        for subclasses of InnerWindow. Other consumers should pass in an
+        appropriate color_theme
+        
+        '''
+        self.border_size = border_size
+        self.selectable = True
+        self.data_obj = data_obj
+        self.on_make_active = None
+        self.on_make_inactive = None
+        self.on_make_active_kwargs = {}
+        self.on_make_inactive_kwargs = {}
+        # We check self.is_pad, so that subclasses can set it prior to
+        # calling InnerWindow.__init__
+        self.is_pad = (getattr(window, "is_pad", False) or
+                        getattr(self, "is_pad", False))
+        self.pad = None
+        self.objects = []
+        self.all_objects = []
+        self.more_windows = []
+        self.active_object = None
+        self.key_dict = None
+        self._init_key_dict()
+        self.area = copy(area)
+        self._adjust_area(window)
+        self.color_theme = color_theme
+        if isinstance(window, InnerWindow):
+            window.add_object(self, at_index=at_index, selectable=add_obj)
+            if self.color_theme is None:
+                self.color_theme = window.color_theme
+        self.window = None
+        self._init_win(window)
+        
+        if color is not None:
+            self.color = color
+        else:
+            self.color = self.color_theme.default
+        
+        if highlight_color is not None:
+            self.highlight_color = highlight_color
+        else:
+            self.highlight_color = self.color
+        
+        self.set_color(self.color)
+        
+        self.window.keypad(1)
+        self.window.leaveok(0)
+    
+    def make_active(self):
+        '''Highlight this window and activate the active_object, if there
+        is one.
+        
+        '''
+        self.set_color(self.highlight_color)
+        if self.objects:
+            if self.active_object is None:
+                self.active_object = 0
+            self.objects[self.active_object].make_active()
+        # pylint: disable-msg=E1102
+        # E1102: <attr> is not callable. However, we're checking that already
+        if callable(self.on_make_active):
+            self.on_make_active(**self.on_make_active_kwargs)
+    
+    def make_inactive(self):
+        '''Mark this window inactive, setting its color back to 'normal'
+        Also make_inactive its active_object.
+        
+        '''
+        self.set_color(self.color)
+        if self.active_object is not None:
+            self.objects[self.active_object].make_inactive()
+        # pylint: disable-msg=E1102
+        # E1102: <attr> is not callable. However, we're checking that already
+        if callable(self.on_make_inactive):
+            self.on_make_inactive(**self.on_make_inactive_kwargs)
+    
+    def activate_object(self, index=0, loop=False):
+        '''Set a specific object to be the active object.
+        
+        This function accepts either an integer index,
+        or an object reference. If an object reference is
+        passed in, it must be an object in this InnerWindow.objects
+        list.
+        
+        if loop == True, integers that are out of bounds of the size of the
+        objects list are shifted to be in bounds. This allows looping from
+        the last item in the list to the first (and vice versa), similar
+        to the syntax for accessing list items.
+        
+        if loop is False, and index is an integer < 0 or > len(self.objects),
+        an IndexError is raised.
+        
+        '''
+        if not isinstance(index, int):
+            index = self.objects.index(index)
+        elif loop:
+            index = index % len(self.objects)
+        elif index < 0 or index >= len(self.objects):
+            err_msg = ("Index (%i) out of range (0-%i)" %
+                       (index, len(self.objects)))
+            raise IndexError(err_msg)
+        if self.active_object is not None:
+            self.objects[self.active_object].make_inactive()
+        self.objects[index].make_active()
+        self.active_object = index
+        logging.log(LOG_LEVEL_INPUT, "Object at index %s now active", self.active_object)
+        self.no_ut_refresh()
+    
+    def add_text(self, text, start_y=0, start_x=0, max_chars=None,
+                 centered=False):
+        '''Add a single line of text to the window
+        
+        'text' must fit within the specified space, or it will be truncated
+        
+        '''
+        win_y, win_x = self.window.getmaxyx()
+        logging.log(LOG_LEVEL_INPUT, "start_y=%d, start_x=%d, max_chars=%s, centered=%s,"
+                    " win_max_x=%s, win_max_y=%s",
+                    start_y, start_x, max_chars, centered, win_x, win_y)
+        max_x = self.window.getmaxyx()[1] - self.border_size[1]
+        start_x += self.border_size[1]
+        if centered:
+            length = len(text)
+            max_x = max_x - start_x
+            if self.window.getmaxyx()[0] == (start_y + 1):
+                max_x -= 1 # Cannot print to bottom-right corner
+            start_x = (max_x - length) / 2 + start_x
+        
+        abs_max_chars = max_x - start_x
+        if max_chars is None:
+            max_chars = abs_max_chars
+        else:
+            max_chars = min(max_chars, abs_max_chars)
+        
+        logging.log(LOG_LEVEL_INPUT, "calling addnstr with params start_y=%s, start_x=%s, "
+                    "text=%s, max_chars=%s", start_y, start_x, text, max_chars)
+        self.window.addnstr(start_y, start_x, text, max_chars)
+        self.no_ut_refresh()
+    
+    @staticmethod
+    def convert_paragraph(text, max_chars):
+        '''Break a paragraph of text up into chunks that will each
+        fit within max_chars. Splits on whitespace and newlines
+        
+        max_chars defaults to the size of this window.
+        
+        '''
+        text_lines = text.expandtabs(4).splitlines()
+        paragraphed_lines = []
+        for line in text_lines:
+            if len(line) <= max_chars:
+                paragraphed_lines.append(line)
+            else:
+                start_pt = 0
+                end_pt = 0
+                while end_pt + max_chars < len(line): 
+                    end_pt = line.rfind(" ", start_pt, start_pt + max_chars)
+                    if end_pt == -1:
+                        end_pt = start_pt + max_chars
+                    paragraphed_lines.append(line[start_pt:end_pt].lstrip())
+                    start_pt = end_pt + 1
+                else:
+                    paragraphed_lines.append(line[end_pt:].lstrip())
+        return paragraphed_lines
+    
+    def add_paragraph(self, text, start_y=0, start_x=0, max_y=None,
+                      max_x=None):
+        '''Add a block of text to the window
+        
+        Add a paragraph to the screen. If a string is passed in, it is
+        converted using convert_paragraph. If a list of strings is passed in,
+        each string will fit in the space alloted (long lines will be
+        truncated). Any lines that would be printed past max_y will not be
+        printed.
+        
+        The number of lines used is returned.
+        
+        '''
+        logging.log(LOG_LEVEL_INPUT, "add_paragraph: start_y=%d, start_x=%d, max_y=%s, "
+                    "max_x=%s", start_y, start_x, max_y, max_x)
+        win_size_y, win_size_x = self.window.getmaxyx()
+        start_y += self.border_size[0]
+        if max_y is None:
+            max_y = win_size_y - start_y - self.border_size[0]
+        if max_x is None:
+            max_x = win_size_x
+        max_chars = max_x - start_x - self.border_size[1] - 1
+        y_index = start_y
+        if isinstance(text, basestring):
+            text = self.convert_paragraph(text, max_chars)
+        for line in text:
+            self.add_text(line, y_index, start_x, max_chars)
+            y_index += 1
+            if y_index > max_y + start_y:
+                logging.warn("Could not fit all text in space for the "
+                             "paragraph. Last line:\n%s", line)
+                break
+        return y_index - start_y
+    
+    def add_object(self, obj, at_index=None, selectable=True):
+        '''Add an InnerWindow) to this window's object list'''
+        if at_index is None:
+            at_index = len(self.objects)
+        if selectable:
+            self.objects.insert(at_index, obj)
+        self.all_objects.append(obj)
+    
+    def remove_object(self, obj):
+        '''Convenience method for removing an object from both self.objects
+        and self.all_objects
+        
+        '''
+        if obj in self.objects:
+            obj_index = self.objects.index(obj)
+            if obj_index == self.active_object:
+                self.active_object = max(0, self.active_object - 1)
+            self.objects.remove(obj)
+        
+        self.all_objects.remove(obj)
+        obj.clear()
+        self.no_ut_refresh()
+    
+    def clear(self):
+        '''Remove all objects from this window's list and clear the screen
+        Also resets the key_dictionary to a default state
+        
+        The background of this window will still be displayed; clear the parent
+        if the window should be removed in entirety
+        
+        '''
+        for obj in self.all_objects:
+            obj.clear()
+        self.objects = []
+        self.all_objects = []
+        self.active_object = None
+        self.window.erase()
+        self.set_color(self.color)
+        self._init_key_dict()
+    
+    def on_key_down(self, input_key):
+        '''On curses.KEY_DOWN:
+        Move to the next active_object, if this window is handling objects.
+        If already at the last object, let the parent handle the keystroke.
+        
+        '''
+        logging.log(LOG_LEVEL_INPUT, "InnerWindow.on_key_down\n%s", type(self))
+        if self.active_object is not None:
+            try:
+                self.activate_object(self.active_object + 1)
+                return None
+            except IndexError:
+                return input_key
+        else:
+            return input_key
+    
+    def on_key_up(self, input_key):
+        '''On curses.KEY_UP:
+        Move to the previous active_object, if this window is handling objects.
+        If already at the first object, let the parent handle the keystroke.
+        
+        '''
+        logging.log(LOG_LEVEL_INPUT, "InnerWindow.on_key_up")
+        if self.active_object is not None:
+            try:
+                self.activate_object(self.active_object - 1)
+                return None
+            except IndexError:
+                return input_key
+        else:
+            return input_key
+    
+    def process(self, input_key):
+        '''Process keyboard input
+        
+        Keyboard input is handled in a "bottom-up" manner. If this window
+        has an active object, the input is passed down to it. If the input
+        isn't handled by the object, this object tries to handle it. If it
+        can't handle it, the keystroke is passed back up the chain.
+        
+        '''
+        if self.active_object is not None:
+            input_key = self.objects[self.active_object].process(input_key)
+        if input_key is None:
+            return input_key
+        else:
+            handler = self.key_dict.get(input_key, no_action)
+            return handler(input_key)
+    
+    def _init_key_dict(self):
+        '''Map some keystrokes by default:
+        
+        KEY_DOWN -> InnerWindow.on_key_down
+        KEY_UP -> InnerWindow.on_key_up
+        
+        '''
+        self.key_dict = {}
+        self.key_dict[curses.KEY_DOWN] = self.on_key_down
+        self.key_dict[curses.KEY_UP] = self.on_key_up
+        self.key_dict[curses.KEY_LEFT] = no_action
+        self.key_dict[curses.KEY_RIGHT] = no_action
+        self.key_dict[InnerWindow.REPAINT_KEY] = no_action
+    
+    @staticmethod
+    def translate_input(input_key):
+        '''Translate keyboard input codes
+        
+        This function will translate keyboard input.
+        Its primary job is understanding Esc-# sequences and turning them
+        into F# key codes. It also converts keys as indicated by
+        InnerWindow.KEY_TRANSLATE.
+        
+        '''
+        logging.log(LOG_LEVEL_INPUT, "Got char code %s", input_key)
+        if InnerWindow.BEGIN_ESC:
+            logging.log(LOG_LEVEL_INPUT, "Ending esc-sequence")
+            InnerWindow.BEGIN_ESC = False
+            if curses.ascii.isdigit(input_key):
+                logging.log(LOG_LEVEL_INPUT,
+                            "Valid esc-sequence, converting to KEY_FN")
+                return input_key - ZERO_CHAR + curses.KEY_F0
+            else:
+                logging.log(LOG_LEVEL_INPUT,
+                            "Invalid esc-sequence, returning raw input")
+        elif input_key == KEY_ESC:
+            logging.log(LOG_LEVEL_INPUT, "Beginning esc-sequence")
+            if not InnerWindow.USE_ESC:
+                InnerWindow.USE_ESC = True
+                InnerWindow.UPDATE_FOOTER = True
+            InnerWindow.BEGIN_ESC = True
+            return None
+        input_key = InnerWindow.KEY_TRANSLATE.get(input_key, input_key)
+        return input_key
+    
+    def getch(self):
+        '''InnerWindow.getch() searches downward to the bottom-most
+        active object. If this *is* the bottom-most active object,
+        get the input from the user (blocking, unless self.window.timeout()
+        has been set), translate it, and return it.
+        Once found, the active object's window.getch() function is called.
+        
+        This function is required to ensure that curses.window.getch() is
+        called from the active object. Curses will update the console
+        differently based on which window calls getch()
+        
+        '''
+        if self.active_object is not None:
+            return self.objects[self.active_object].getch()
+        else:
+            try:
+                input_key = self.window.getch()
+                return InnerWindow.translate_input(input_key)
+            except ValueError:
+                return None
+    
+    def get_cursor_loc(self):
+        '''Retrieve the cursor location from the active UI element'''
+        if self.active_object is not None:
+            return self.get_active_object().get_cursor_loc()
+        else:
+            return None
+    
+    def get_active_object(self):
+        '''Convenience method for retrieving the active object.
+        Returns None if no active object is set'''
+        if self.active_object is not None:
+            return self.objects[self.active_object]
+        else:
+            return None
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/install_progress.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,266 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+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.text_install import _, LOG_LEVEL_INPUT
+from osol_install.text_install.base_screen import BaseScreen
+from osol_install.text_install.inner_window import InnerWindow
+from osol_install.text_install.window_area import WindowArea
+from osol_install.text_install.ti_install import perform_ti_install
+
+
+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 OpenSolaris")
+    PROG_BAR_ENDS = (ord('['), ord(']'))
+    
+    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'''
+        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.
+        
+        '''
+        install_profile.disk.to_tgt()
+        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(message.ljust(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,
+                                       BaseScreen.QUIT_DISK_MOD_TEXT,
+                                       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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/install_status.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,112 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Report the status of an installation to the user
+'''
+
+import curses
+
+from osol_install.text_install import _
+from osol_install.text_install.action import Action
+from osol_install.text_install.base_screen import BaseScreen, RebootException
+
+
+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 OpenSolaris 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
+        
+        if self.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.
+        
+        '''
+        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)
+        
+        self.center_win.add_paragraph(paragraph_text % self.log_locations, 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/list_item.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,68 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+UI element for representing a single selectable list item
+'''
+
+from osol_install.text_install.inner_window import InnerWindow
+
+
+class ListItem(InnerWindow):
+    '''
+    Represents a single item selectable from a list
+    '''
+    
+    def __init__(self, area, window=None, color_theme=None, color=None,
+                 highlight_color=None, text="", centered=False, **kwargs):
+        '''
+        See also InnerWindow.__init__
+        
+        Sets color to color_theme.default, and
+        highlight to color_theme.list-field
+        
+        If 'text' is given, adds the text to the display
+        '''
+        if color_theme is None:
+            color_theme = window.color_theme
+        if color is None:
+            color = color_theme.default
+        if highlight_color is None:
+            highlight_color = color_theme.list_field
+        super(ListItem, self).__init__(area, window=window,
+                                       color_theme=color_theme, 
+                                       color=color,
+                                       highlight_color=highlight_color,
+                                       **kwargs)
+        self.set_text(text, centered)
+    
+    def set_text(self, text, centered=False):
+        '''Set the text of this ListItem. Shortcut to InnerWindow.add_text
+        ensures that this window is cleared first
+        
+        '''
+        self.window.clear()
+        self.add_text(text, max_chars=(self.window.getmaxyx()[1] - 1),
+                      centered=centered)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/log_viewer.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,83 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Read in and display the install log to the user
+'''
+
+import curses
+
+from osol_install.text_install import _
+from osol_install.text_install.base_screen import BaseScreen
+from osol_install.text_install.inner_window import InnerWindow
+from osol_install.text_install.scroll_window import ScrollWindow
+from osol_install.text_install.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'''
+        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 = InnerWindow.convert_paragraph(log_data, max_chars)
+        return self.log_data
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/main_window.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,317 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Window that represents the entire terminal, and 'top-level' functions,
+such as capturing keystrokes that will change the screen
+'''
+
+import curses
+from curses.ascii import ctrl
+
+from osol_install.text_install import _
+from osol_install.text_install.color_theme import ColorTheme
+from osol_install.text_install.action import Action
+from osol_install.text_install.error_window import ErrorWindow
+from osol_install.text_install.inner_window import InnerWindow
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.scroll_window import ScrollWindow
+from osol_install.text_install.window_area import WindowArea
+
+
+class MainWindow(object):
+    '''Represent initscr (the whole screen), and break it into a border,
+    header, and central region. Map F# keystrokes to Actions
+    
+    '''
+    
+    def __init__(self, initscr, screen_list, theme=None, force_bw=False):
+        '''Set the theme, and call reset to initialize the terminal to
+        prepare for the first screen.
+        
+        '''
+        
+        if theme is not None:
+            self.theme = theme
+        else:
+            self.theme = ColorTheme(force_bw=force_bw)
+        self.screen_list = screen_list
+        self.initscr = initscr
+        self.default_cursor_pos = (initscr.getmaxyx()[0] - 1, 0)
+        self.cursor_pos = self.default_cursor_pos
+        self.footer = None
+        self.header = None
+        self._cur_header_text = None
+        self.central_area = None
+        self.popup_win = None
+        self.error_line = None
+        self._active_win = None
+        self.continue_action = None
+        self.back_action = None
+        self.help_action = None
+        self.quit_action = None
+        self.actions = None
+        self.reset()
+    
+    def redrawwin(self):
+        '''Completely repaint the screen'''
+        self.header.redrawwin()
+        self.footer.redrawwin()
+        self.error_line.redrawwin()
+        self.central_area.redrawwin()
+        if self._active_win is self.popup_win:
+            self.popup_win.redrawwin()
+    
+    def do_update(self):
+        '''Wrapper to curses.doupdate()'''
+        curses.setsyx(*self.get_cursor_loc())
+        curses.doupdate()
+    
+    def get_cursor_loc(self):
+        '''Retrieve the current cursor position from the active UI
+        element.
+        
+        '''
+        cursor = self.central_area.get_cursor_loc()
+        if cursor is None:
+            cursor = self.cursor_pos
+        return cursor
+    
+    def reset(self):
+        '''Create the InnerWindows representing the header, footer/border,
+        error line, and main central_area
+        
+        '''
+        window_size = self.initscr.getmaxyx()
+        win_size_y = window_size[0]
+        win_size_x = window_size[1]
+        footer_area = WindowArea(1, win_size_x, win_size_y - 1, 0)
+        self.footer = InnerWindow(footer_area, color_theme=self.theme,
+                                  color=self.theme.border)
+        top = self.initscr.derwin(1, win_size_x, 0, 0)
+        left = self.initscr.derwin(win_size_y - 2, 1, 1, 0)
+        right = self.initscr.derwin(win_size_y - 2, 1, 1, win_size_x - 1)
+        self.footer.more_windows = [top, left, right]
+        self.footer.set_color(self.theme.border)
+        header_area = WindowArea(1, win_size_x - 2, 1, 1)
+        self.header = InnerWindow(header_area, color_theme=self.theme,
+                                  color=self.theme.header)
+        central_win_area = WindowArea(win_size_y - 4, win_size_x - 2, 2, 1)
+        self.central_area = InnerWindow(central_win_area,
+                                        border_size=(0, 2),
+                                        color_theme=self.theme)
+        self._active_win = self.central_area
+        popup_win_area = WindowArea(central_win_area.lines - 10,
+                                    central_win_area.columns - 20,
+                                    5, 10, central_win_area.lines - 10)
+        self.popup_win = ScrollWindow(popup_win_area, window=self.central_area,
+                                      color=self.theme.error_msg,
+                                      highlight_color=self.theme.error_msg)
+        error_area = WindowArea(1, win_size_x - 2, win_size_y - 2, 1)
+        self.error_line = ErrorWindow(error_area, color_theme=self.theme)
+        self.reset_actions()
+    
+    def reset_actions(self):
+        '''Reset the actions to the defaults, clearing any custom actions
+        registered by individual screens
+        
+        '''
+        self.continue_action = Action(curses.KEY_F2, _("Continue"),
+                                      self.screen_list.get_next)
+        self.back_action = Action(curses.KEY_F3, _("Back"),
+                                  self.screen_list.previous_screen)
+        self.help_action = Action(curses.KEY_F6, _("Help"),
+                                  self.screen_list.show_help)
+        self.quit_action = Action(curses.KEY_F9, _("Quit"),
+                                  self.screen_list.quit)
+        self.set_default_actions()
+    
+    def clear(self):
+        '''Clear all InnerWindows and reset_actions()'''
+        self.header.clear()
+        self.footer.clear()
+        self.central_area.clear()
+        self.error_line.clear_err()
+        self.reset_actions()
+    
+    def set_header_text(self, header_text):
+        '''Set the header_text'''
+        text = header_text.center(self.header.area.columns - 1)
+        self.header.add_text(text)
+        self._cur_header_text = text
+    
+    def set_default_actions(self):
+        '''Clear the actions dictionary and add the default actions back
+        into it
+        
+        '''
+        self.actions = {}
+        self.actions[self.continue_action.key] = self.continue_action
+        self.actions[self.back_action.key] = self.back_action
+        self.actions[self.help_action.key] = self.help_action
+        self.actions[self.quit_action.key] = self.quit_action
+        
+    def show_actions(self):
+        '''Read through the actions dictionary, displaying all the actions
+        descriptive text along the footer (along with a prefix linked to
+        its associated keystroke)
+        
+        '''
+        self.footer.window.clear()
+        if InnerWindow.USE_ESC:
+            prefix = " Esc-"
+        else:
+            prefix = "  F"
+        strings = []
+        length = 0
+        action_format = "%s%i_%s"
+        for key in sorted(self.actions.keys()):
+            key_num = key - curses.KEY_F0
+            action_text = self.actions[key].text
+            action_str = action_format % (prefix, key_num, action_text)
+            strings.append(action_str)
+        display_str = "".join(strings)
+        max_len = self.footer.window.getmaxyx()[1]
+        length = len(display_str)
+        if not InnerWindow.USE_ESC:
+            length += (len(" Esc-") - len("  F")) * len(self.actions)
+        if length > max_len:
+            raise ValueError("Can't display footer actions - string too long")
+        self.footer.window.addstr(display_str)
+        self.footer.window.noutrefresh()
+    
+    def getch(self):
+        '''Call down into central_area to get a keystroke, and, if necessary,
+        update the footer to switch to using the Esc- prefixes
+        
+        '''
+        input_key = self._active_win.getch()
+        if input_key == InnerWindow.REPAINT_KEY:
+            self.redrawwin()
+            input_key = None
+        if InnerWindow.UPDATE_FOOTER:
+            InnerWindow.UPDATE_FOOTER = False
+            self.show_actions()
+        return input_key
+    
+    def process_input(self, current_screen):
+        '''Read input until a keystroke that fires a screen change
+        is caught
+        
+        '''
+        input_key = None
+        while input_key not in self.actions:
+            input_key = self.getch()
+            input_key = self.central_area.process(input_key)
+            self.do_update()
+        return self.actions[input_key].do_action(current_screen)
+    
+    def pop_up(self, header, question, left_btn_txt, right_btn_txt,
+               color=None):
+        '''Suspend the current screen, setting the header
+        to 'header', presenting the 'question,' and providing two 'buttons'.
+        Returns True if the RIGHT button is selected, False if the LEFT is
+        selected. The LEFT button is initially selected.
+        
+        '''
+        
+        
+        # Hide the cursor, storing its previous state (visibility) so
+        # it can be restored when finished. Then, move the cursor
+        # to the default position (in case this terminal type does not support
+        # hiding the cursor entirely)
+        try:
+            old_cursor_state = curses.curs_set(0)
+        except curses.error:
+            old_cursor_state = 2
+        cursor_loc = curses.getsyx()
+        curses.setsyx(self.cursor_pos[0], self.cursor_pos[1])
+        
+        # Add the header, a border, and the question to the window
+        self.popup_win.window.border()
+        header_x = (self.popup_win.area.columns - len(header)) / 2
+        self.popup_win.add_text(header, 0, header_x)
+        y_loc = 2
+        y_loc += self.popup_win.add_paragraph(question, y_loc, 2)
+        y_loc += 2
+        
+        
+        # Set the background color based on the parameter given, or choose
+        # a default based on the theme. Set the highlight_color by flipping
+        # the A_REVERSE bit of the color
+        if color is None:
+            color = self.popup_win.color
+        self.popup_win.set_color(color)
+        highlight_color = color ^ curses.A_REVERSE
+        
+        # Create two "buttons" of equal size by finding the larger of the
+        # two, and centering them
+        max_len = max(len(left_btn_txt), len(right_btn_txt))
+        left_btn_txt = " [ %s ]" % left_btn_txt.center(max_len)
+        right_btn_txt = " [ %s ]" % right_btn_txt.center(max_len)
+        button_len = len(left_btn_txt) + 1
+        win_size = self.popup_win.window.getmaxyx()
+        left_area = WindowArea(1, button_len, y_loc,
+                               (win_size[1] / 2) - (button_len + 2))
+        left_button = ListItem(left_area, window=self.popup_win,
+                               text=left_btn_txt, color=color,
+                               highlight_color=highlight_color)
+        right_area = WindowArea(1, button_len, y_loc, win_size[1] / 2 + 2)
+        right_button = ListItem(right_area, window=self.popup_win,
+                                text=right_btn_txt, color=color,
+                                highlight_color=highlight_color)
+        
+        # Highlight the left button, clear any errors on the screen,
+        # and display the pop up
+        self.popup_win.activate_object(left_button)
+        self.popup_win.no_ut_refresh()
+        self.error_line.clear_err()
+        self.do_update()
+        
+        self._active_win = self.popup_win
+        # Loop until the user selects an option.
+        input_key = None
+        while input_key != curses.KEY_ENTER:
+            input_key = self.getch()
+            input_key = self.popup_win.process(input_key)
+            if input_key == curses.KEY_LEFT:
+                self.popup_win.activate_object(left_button)
+            elif input_key == curses.KEY_RIGHT:
+                self.popup_win.activate_object(right_button)
+            self.do_update()
+        self._active_win = self.central_area
+        user_selected = (self.popup_win.get_active_object() is right_button)
+        
+        # Clear the pop up and restore the previous screen, including the
+        # cursor position and visibility
+        self.popup_win.clear()
+        self.central_area.redrawwin()
+        curses.setsyx(cursor_loc[0], cursor_loc[1])
+        try:
+            curses.curs_set(old_cursor_state)
+        except curses.error:
+            pass
+        self.do_update()
+        
+        return user_selected
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/network_nic_configure.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,243 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Allow user to configure a single NIC with manual network information
+'''
+
+import logging
+
+from osol_install.profile.ip_address import IPAddress
+from osol_install.profile.network_info import NetworkInfo
+from osol_install.text_install import _
+from osol_install.text_install.base_screen import BaseScreen, \
+                                                  SkipException, \
+                                                  UIMessage
+from osol_install.text_install.edit_field import EditField
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.window_area import WindowArea
+
+class NICConfigure(BaseScreen):
+    '''
+    Manually configure a single NIC to use a static IP
+    '''
+    
+    HEADER_TEXT = _("Manually Configure: %s")
+    
+    PARAGRAPH = _("Enter the configuration for the this network"
+                  " connection. All entries, except Domain, "
+                  "must contain four sets of numbers, 0 to 255,"
+                  " separated by periods.")
+    IP_LABEL = _("IP Address:")
+    IP_DESCRIPTION = _("Must be unique for this network")
+    NETMASK_LABEL = _("Netmask:")
+    NETMASK_DESCRIPTION = _("Your subnet use may require a different mask")
+    GATEWAY_LABEL = _("Gateway:")
+    GATEWAY_DESCRIPTION = _("The IP address of the gateway on this subnet")
+    DNS_LABEL = _("DNS:")
+    DNS_FOUND = _("A DNS server was found on the network")
+    DNS_NOT_FOUND = _("Address of the Domain Name Server")
+    DOMAIN_LABEL = _("Domain:")
+    DOMAIN_FOUND = _("The machine appears to be in this domain")
+    DOMAIN_NOT_FOUND = _("The network's domain name")
+    
+    ITEM_OFFSET = 2
+    EDIT_FIELD_LEN = 16
+    
+    
+    def __init__(self, main_win):
+        super(NICConfigure, self).__init__(main_win)
+        self.dns_description = None
+        self.domain_description = None
+        item_length = max(len(NICConfigure.IP_LABEL),
+                          len(NICConfigure.NETMASK_LABEL),
+                          len(NICConfigure.GATEWAY_LABEL),
+                          len(NICConfigure.DNS_LABEL),
+                          len(NICConfigure.DOMAIN_LABEL))
+        item_length += 1
+        list_width = item_length + NICConfigure.EDIT_FIELD_LEN
+        self.list_area = WindowArea(1, list_width, 0, NICConfigure.ITEM_OFFSET)
+        self.edit_area = WindowArea(1, NICConfigure.EDIT_FIELD_LEN, 0,
+                                    item_length)
+        self.ip_field = None
+        self.netmask_field = None
+        self.gateway_field = None
+        self.dns_field = None
+        self.domain_field = None
+        self.nic = None
+    
+    def _show(self):
+        '''Create the editable fields for IP address, netmask, gateway,
+        dns address and dns domain
+        
+        '''
+        self.nic = self.install_profile.nic
+        if self.nic.type != NetworkInfo.MANUAL:
+            raise SkipException
+        
+        nic_name = self.nic.nic_name
+        
+        if self.nic.find_defaults:
+            self.set_defaults(self.nic)
+        
+        self.main_win.set_header_text(NICConfigure.HEADER_TEXT % nic_name)
+        
+        max_y = self.win_size_y - 16
+        max_x = self.win_size_x - 1
+        y_loc = 1
+        y_loc += self.center_win.add_paragraph(NICConfigure.PARAGRAPH, y_loc,
+                                               max_y=max_y)
+        
+        max_y = 3
+        description_start = (NICConfigure.ITEM_OFFSET * 2 +
+                             self.list_area.columns)
+        y_loc += 1
+        
+        self.ip_field = self.make_field(NICConfigure.IP_LABEL,
+                                        NICConfigure.IP_DESCRIPTION,
+                                        y_loc, max_y, max_x,
+                                        description_start,
+                                        self.nic.ip_address)
+        
+        y_loc += max_y
+        self.netmask_field = self.make_field(NICConfigure.NETMASK_LABEL,
+                                             NICConfigure.NETMASK_DESCRIPTION,
+                                             y_loc, max_y, max_x,
+                                             description_start,
+                                             self.nic.netmask)
+        
+        y_loc += max_y
+        self.gateway_field = self.make_field(NICConfigure.GATEWAY_LABEL,
+                                             NICConfigure.GATEWAY_DESCRIPTION,
+                                             y_loc, max_y, max_x,
+                                             description_start,
+                                             self.nic.gateway)
+        
+        y_loc += max_y
+        self.dns_field = self.make_field(NICConfigure.DNS_LABEL,
+                                         self.dns_description,
+                                         y_loc, max_y, max_x,
+                                         description_start,
+                                         self.nic.dns_address)
+        
+        y_loc += max_y
+        self.domain_field = self.make_field(NICConfigure.DOMAIN_LABEL,
+                                            self.domain_description, y_loc,
+                                            max_y, max_x, description_start,
+                                            self.nic.domain,
+                                            is_ip=False)
+        
+        self.main_win.do_update()
+        self.center_win.activate_object()
+    
+    def make_field(self, label, description, y_loc, max_y, max_x,
+                   description_start, default_val, is_ip=True):
+        '''Create a list item with 'label', add an editable field with
+        'default_val', and add additional 'description' text following it
+        
+        '''
+        self.list_area.y_loc = y_loc
+        list_item = ListItem(self.list_area, text=label, data_obj=label,
+                             window=self.center_win)
+        if is_ip:
+            validate = incremental_validate_IP
+        else:
+            validate = None
+        edit_field = EditField(self.edit_area, window=list_item,
+                               text=default_val, validate=validate,
+                               error_win=self.main_win.error_line,
+                               data_obj=label.rstrip(":"))
+        self.center_win.add_paragraph(description, y_loc, description_start,
+                                      max_y=(y_loc + max_y), max_x=max_x)
+        return edit_field
+    
+    def validate(self):
+        '''Verify the syntactical validity of the IP Address fields'''
+        ip_fields = [self.ip_field,
+                     self.netmask_field,
+                     self.gateway_field,
+                     self.dns_field]
+        for field in ip_fields:
+            validate_ip(field)
+        
+        if not self.ip_field.get_text():
+            raise UIMessage(_("IP Address must not be empty"))
+        if not self.netmask_field.get_text():
+            raise UIMessage(_("Netmask must not be empty"))
+        if self.domain_field.get_text() and not self.dns_field.get_text():
+            raise UIMessage(_("DNS server required if Domain set"))
+    
+    def on_change_screen(self):
+        '''Preserve all data on screen changes'''
+        self.nic.ip_address = self.ip_field.get_text()
+        self.nic.netmask = self.netmask_field.get_text()
+        self.nic.gateway = self.gateway_field.get_text()
+        self.nic.dns_address = self.dns_field.get_text()
+        self.nic.domain = self.domain_field.get_text()
+        self.nic.find_defaults = False
+        logging.debug("Setting network to:\n%s", self.nic)
+    
+    def set_defaults(self, nic):
+        '''Attempt to find DNS information for the selected NIC, and update
+        the descriptive text based on the result
+        
+        '''
+        if nic.find_dns():
+            self.dns_description = NICConfigure.DNS_FOUND
+        else:
+            self.dns_description = NICConfigure.DNS_NOT_FOUND
+        if nic.find_domain():
+            self.domain_description = NICConfigure.DOMAIN_FOUND
+        else:
+            self.domain_description = NICConfigure.DOMAIN_NOT_FOUND
+
+
+def validate_ip(edit_field):
+    '''Wrap a call to IPAddress.check_address and raise a UIMessage with
+    appropriate message text
+    
+    '''
+    ip_address = edit_field.get_text()
+    if not ip_address:
+        return True
+    try:
+        IPAddress.convert_address(ip_address)
+    except ValueError:
+        raise UIMessage(_("%s must be of the form xxx.xxx.xxx.xxx") %
+                        edit_field.data_obj)
+    return True
+
+# pylint: disable-msg=C0103
+# IP is an abbreviation and appropriately capitalized here
+def incremental_validate_IP(edit_field):
+    '''Incrementally validate the IP Address as the user enters it'''
+    ip_address = edit_field.get_text()
+    if not ip_address:
+        return True
+    try:
+        IPAddress.incremental_check(ip_address)
+    except ValueError:
+        raise UIMessage(_("%s must be of the form xxx.xxx.xxx.xxx") %
+                        edit_field.data_obj)
+    return True
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/network_nic_select.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,110 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Support for allowing the user to select a NIC to configure
+'''
+
+import logging
+
+from osol_install.profile.network_info import NetworkInfo
+from osol_install.text_install import _
+from osol_install.text_install.base_screen import BaseScreen, SkipException
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.scroll_window import ScrollWindow
+from osol_install.text_install.window_area import WindowArea
+
+
+class NICSelect(BaseScreen):
+    '''Allow user to choose which ethernet connection to manually configure'''
+    
+    MAX_NICS = 15
+    
+    HEADER_TEXT = _("Manual Network Configuration")
+    PARAGRAPH = _("Select the one wired network connection to be configured"
+                  " during installation")
+    
+    LIST_OFFSET = 2
+    
+    def __init__(self, main_win):
+        super(NICSelect, self).__init__(main_win)
+        self.list_area = WindowArea(1, 0, 0, NICSelect.LIST_OFFSET)
+        self.ether_nics = NetworkInfo.find_links()
+        self.nic = None
+    
+    def _show(self):
+        '''Create a list of NICs to choose from. If more than 15 NICs are
+        found, create a scrolling region to put them in
+        
+        '''
+        self.nic = self.install_profile.nic
+        if self.nic.type != NetworkInfo.MANUAL:
+            raise SkipException
+        if len(self.ether_nics) == 1:
+            self.set_nic_in_profile(self.ether_nics[0])
+            raise SkipException
+        
+        try:
+            selected_nic_name = self.nic.nic_name
+        except AttributeError:
+            selected_nic_name = ""
+        
+        y_loc = 1
+        y_loc += self.center_win.add_paragraph(NICSelect.PARAGRAPH, y_loc)
+        
+        selected_nic = 0
+        
+        y_loc += 1
+        max_nics = min(NICSelect.MAX_NICS, self.center_win.area.lines - y_loc)
+        if len(self.ether_nics) > max_nics:
+            columns = self.win_size_x - NICSelect.LIST_OFFSET
+            win_area = WindowArea(lines=max_nics, columns=columns,
+                                  y_loc=y_loc, x_loc=NICSelect.LIST_OFFSET,
+                                  scrollable_lines=len(self.ether_nics))
+            window = ScrollWindow(win_area, window=self.center_win)
+            y_loc = 0
+        else:
+            window = self.center_win
+        
+        for nic in self.ether_nics:
+            self.list_area.y_loc = y_loc
+            self.list_area.columns = len(nic) + 1
+            list_item = ListItem(self.list_area, window=window, text=nic,
+                                 data_obj=nic)
+            if nic == selected_nic_name:
+                selected_nic = list_item
+            y_loc += 1
+        
+        self.main_win.do_update()
+        self.center_win.activate_object(selected_nic)
+    
+    def on_change_screen(self):
+        '''Save the highlighted NIC as the selected NIC'''
+        selected_nic = self.center_win.get_active_object().data_obj
+        self.set_nic_in_profile(selected_nic)
+    
+    def set_nic_in_profile(self, selected_nic):
+        '''Set the name of the selected NIC in the profile '''
+        logging.info("Selecting %s for manual configuration", selected_nic)
+        self.install_profile.nic.nic_name = selected_nic
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/network_type.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,206 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Support for editing the hostname and, if any wired NICs are found, selecting
+how to configure them
+'''
+
+import logging
+
+from osol_install.profile.network_info import NetworkInfo
+from osol_install.profile.system_info import SystemInfo
+from osol_install.text_install import _
+from osol_install.text_install.base_screen import BaseScreen, UIMessage
+from osol_install.text_install.edit_field import EditField
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.window_area import WindowArea
+
+
+class NetworkTypeScreen(BaseScreen):
+    '''
+    Let the user:
+    - Choose the hostname
+    - Select network type (Automatic, Manual, or None)
+    '''
+    
+    HEADER_TEXT = _("Network")
+    PARAGRAPH = _("Enter a name for this computer that identifies it on "
+                  "the network. It must be at least two characters. It "
+                  "can contain letters, numbers, and minus signs (-).")
+    HOSTNAME_TEXT = _("Computer Name: ")
+    NET_TYPE_TEXT = _("Select how the wired ethernet network "
+                      "connection is configured.")
+    AUTO_TEXT = _("Automatically")
+    AUTO_DETAIL = _("Automatically configure the connection")
+    MANUAL_TEXT = _("Manually")
+    MANUAL_DETAIL = _("Enter the information on the following screen")
+    NONE_TEXT = _("None")
+    NONE_DETAIL = _("Do not configure the network at this time")
+    NO_NICS_FOUND = _("No wired network interfaces found. Additional "
+                      "device drivers may be needed.")
+    
+    ITEM_OFFSET = 2
+    ITEM_MAX_WIDTH = 17
+    ITEM_DESC_OFFSET = ITEM_MAX_WIDTH + ITEM_OFFSET + 1
+    
+    def __init__(self, main_win):
+        super(NetworkTypeScreen, self).__init__(main_win)
+        self.hostfield_offset = len(NetworkTypeScreen.HOSTNAME_TEXT)
+        self.menu_item_desc_max = (self.win_size_x -
+                                   NetworkTypeScreen.ITEM_DESC_OFFSET)
+        
+        self.net_type_dict = {}
+        self.sys_info = None
+        self.automatic = None
+        self.manual = None
+        self.none_option = None
+        self.hostname = None
+        self.nic_info = NetworkInfo()
+        self.ether_nics = NetworkInfo.find_links()
+        self.have_nic = True
+        if len(self.ether_nics) == 0:
+            self.have_nic = False
+    
+    def _show(self):
+        '''Create an EditField for entering hostname, and list items
+        for each of the network types
+        
+        '''
+        if self.install_profile.system is None:
+            self.install_profile.system = SystemInfo()
+        self.sys_info = self.install_profile.system
+        if self.install_profile.nic is None:
+            self.install_profile.nic = self.nic_info
+        
+        y_loc = 1
+        
+        y_loc += self.center_win.add_paragraph(NetworkTypeScreen.PARAGRAPH,
+                                               y_loc)
+        
+        y_loc += 1
+        self.center_win.add_text(NetworkTypeScreen.HOSTNAME_TEXT, y_loc)
+        
+        cols = self.win_size_x - self.hostfield_offset
+        hostname_area = WindowArea(1, cols, y_loc, self.hostfield_offset)
+        self.hostname = EditField(hostname_area, 
+                                  window=self.center_win,
+                                  text=self.sys_info.hostname,
+                                  validate=hostname_is_valid,
+                                  error_win=self.main_win.error_line)
+        self.hostname.item_key = None
+        
+        y_loc += 3
+        
+        if not self.have_nic:
+            self.center_win.add_paragraph(NetworkTypeScreen.NO_NICS_FOUND,
+                                          y_loc, 1)
+            self.main_win.do_update()
+            activate = self.net_type_dict.get(self.nic_info.type,
+                                              self.hostname)
+            self.center_win.activate_object(activate)
+            return
+        
+        y_loc += self.center_win.add_paragraph(NetworkTypeScreen.NET_TYPE_TEXT,
+                                               y_loc)
+        
+        y_loc += 1
+        item_area = WindowArea(1, NetworkTypeScreen.ITEM_MAX_WIDTH, y_loc,
+                               NetworkTypeScreen.ITEM_OFFSET)
+        self.automatic = ListItem(item_area, window=self.center_win,
+                                  text=NetworkTypeScreen.AUTO_TEXT)
+        self.automatic.item_key = NetworkInfo.AUTOMATIC
+        self.net_type_dict[self.automatic.item_key] = self.automatic
+        self.center_win.add_text(NetworkTypeScreen.AUTO_DETAIL, y_loc,
+                                 NetworkTypeScreen.ITEM_DESC_OFFSET,
+                                 self.menu_item_desc_max)
+        
+        # Until availability of api to allow configuration of
+        # static ip, manual configuration is not available for actual
+        # installations.
+        # If the installer is run with a '-n' flag (for "no install mode"),
+        # the manual network screens are shown (this is for debugging and
+        # testing purposes)
+        if self.install_profile.no_install_mode:
+            y_loc += 2
+            item_area.y_loc = y_loc
+            self.manual = ListItem(item_area, window=self.center_win,
+                                   text=NetworkTypeScreen.MANUAL_TEXT)
+            self.manual.item_key = NetworkInfo.MANUAL
+            self.net_type_dict[self.manual.item_key] = self.manual
+            self.center_win.add_text(NetworkTypeScreen.MANUAL_DETAIL, y_loc,
+                                     NetworkTypeScreen.ITEM_DESC_OFFSET,
+                                     self.menu_item_desc_max)
+        
+        y_loc += 2
+        item_area.y_loc = y_loc
+        self.none_option = ListItem(item_area, window=self.center_win,
+                                    text=NetworkTypeScreen.NONE_TEXT)
+        self.none_option.item_key = NetworkInfo.NONE
+        self.net_type_dict[self.none_option.item_key] = self.none_option
+        self.center_win.add_text(NetworkTypeScreen.NONE_DETAIL, y_loc,
+                                 NetworkTypeScreen.ITEM_DESC_OFFSET,
+                                 self.menu_item_desc_max)
+        
+        self.main_win.do_update()
+        activate = self.net_type_dict.get(self.nic_info.type,
+                                          self.hostname)
+        self.center_win.activate_object(activate)
+    
+    def on_change_screen(self):
+        '''Save hostname and selected network type on change screen'''
+        if self.have_nic:
+            self.nic_info.type = self.center_win.get_active_object().item_key
+        else:
+            self.nic_info.type = NetworkInfo.NONE
+        logging.info("Configuring NIC as: %s", self.nic_info.type)
+        self.sys_info.hostname = self.hostname.get_text()
+    
+    def validate(self):
+        '''Ensure hostname is set and a network type is chosen (unless no
+        NICs are present)
+        
+        '''
+        hostname_text = self.hostname.get_text()
+        if not hostname_text:
+            raise UIMessage(_("A Hostname is required."))
+        if len(hostname_text) < 2:
+            raise UIMessage(_("A Hostname must be at least two characters."))
+        if self.have_nic:
+            item_key = self.center_win.get_active_object().item_key
+            if item_key not in self.net_type_dict:
+                raise UIMessage(_("Select the wired network configuration: "
+                                   "Automatically or None."))
+                                  # "Automatically, Manually, or None."))
+
+
+def hostname_is_valid(edit_field):
+    '''Check hostname for characters other than a-zA-Z0-9 and hyphens'''
+    user_str = edit_field.get_text()
+    if not user_str:
+        return True
+    test_str = user_str.replace(u"-", "a")
+    if not test_str.isalnum():
+        raise UIMessage(_("The Hostname can only contain letter, numbers, "
+                            "and minus signs (-)."))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/partition_edit_screen.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,245 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+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.text_install.action import Action
+from osol_install.text_install.base_screen import BaseScreen, \
+                                                  SkipException, \
+                                                  UIMessage
+from osol_install.text_install.disk_window import DiskWindow, get_minimum_size
+from osol_install.text_install.window_area import WindowArea
+from osol_install.text_install import _
+
+class PartEditScreen(BaseScreen):
+    '''Allows user editing of partitions on a disk, or slices on a
+    disk/partition
+    
+    '''
+    
+    PARTITION_PARAGRAPH = _("OpenSolaris 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.")
+    SLICE_PARAGRAPH = _("OpenSolaris 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")
+    
+    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
+        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
+        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.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'''
+        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}
+        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 += 2
+        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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/screen_list.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,97 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Manage the UI state as two lists of screens:
+(1) The list of screens that could be visited, in the order they should
+be visited
+(2) The list of screens that has been visited
+'''
+
+
+import logging
+
+
+class ScreenList(object):
+    '''Manage the screen lists'''
+    
+    def __init__(self):
+        self.screen_list = []
+        self.visited_list = []
+        self.help = None
+    
+    def get_next(self, current=None, skipped=False):
+        '''Add the current screen to the visited list (unless skipped == True)
+        and return the next screen
+        
+        '''
+        if current is not None:
+            if not skipped:
+                self.visited_list.append(current)
+            current_index = self.screen_list.index(current) + 1
+            if current_index < len(self.screen_list):
+                return self.screen_list[current_index]
+            else:
+                return None
+        else:
+            return self.screen_list[0]
+    
+    def previous_screen(self, dummy=None):
+        '''Return the previous screen.
+        Note that there is no protection against popping from an empty list.
+        This is intentional - the F3_Back action should be removed from the
+        action dictionary of the first screen.
+        
+        '''
+        return self.visited_list.pop()
+    
+    def peek_last(self):
+        '''Peek at the last visited screen. This function can be used to
+        determine if the user is moving forward or backward
+        (see BaseScreen.validate_loop)
+        
+        '''
+        if len(self.visited_list) == 0:
+            return None
+        else:
+            return self.visited_list[-1]
+    
+    @staticmethod
+    def quit(dummy=None):
+        '''Immediately return None (causing an exit)'''
+        logging.debug("screen_list.quit triggered")
+        return None
+
+    def show_help(self, current=None):
+        '''Return the screen registered as the Help Screen.
+        
+        current is appended to the visited_list, unless the current screen
+        is also the help screen.
+        
+        '''
+        logging.debug("show_help: current=%s", current)
+        if (current != self.help):
+            self.visited_list.append(current)
+        self.help.screen = current.__class__.__name__ + current.instance
+        return self.help
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/scroll_window.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,253 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+UI component allowing subwindows that scroll.
+Similar to InnerWindow
+'''
+
+import curses
+import logging
+
+from osol_install.text_install import LOG_LEVEL_INPUT
+from osol_install.text_install.inner_window import InnerWindow
+
+
+class ScrollWindow(InnerWindow):
+    '''A ScrollWindow is an InnerWindow that can scroll
+    
+    Scrolling is currently limited to up/down. Left/right could be
+    added later if needed.
+    
+    Note: When adding objects to this window, remember that the
+    left 2 columns are reserved for the scroll bar.
+    
+    '''
+    
+    def redrawwin(self):
+        '''Mark this ScrollWindow and its children so that they get
+        completely repainted on the next screen update.
+        
+        '''
+        self.window.touchwin()
+        for win in self.more_windows:
+            win.touchwin()
+        for obj in self.all_objects:
+            obj.redrawwin()
+        self.no_ut_refresh()
+    
+    def _init_win(self, dummy):
+        '''Initialize a curses.pad object of appropriate size'''
+        self.window = curses.newpad(self.area.scrollable_lines,
+                                    self.area.columns)
+        self.area.lines -= 1
+        self.area.lower_right_y = self.area.y_loc + self.area.lines
+        self.area.lower_right_x = self.area.x_loc + self.area.columns
+    
+    def __init__(self, area, **kwargs):
+        '''ScrollWindow Constructor. See also InnerWindow.__init__
+        
+        area (required) - For ScrollWindows, area.scrollable_lines must be
+        set. It indicates the height of the scrollable area. The other
+        parameters indicate the width and size of the visible portion
+        of the window.
+        
+        All other parameters are used as in InnerWindow.__init__
+        
+        '''
+        self.bottom = 0
+        self.current_line = 0
+        self._redraw_scroll_bar = True
+        if (area.scrollable_lines > area.lines):
+            self.bottom = area.scrollable_lines - area.lines
+        self._use_scroll_bar = (self.bottom > 1)
+        super(ScrollWindow, self).__init__(area, **kwargs)
+        self.is_pad = True
+        self.pad = self
+        self.no_ut_refresh()
+    
+    def set_use_scroll_bar(self, use_scroll_bar):
+        '''Setter for self.use_scroll_bar. Triggers a redraw of the scroll
+        bar on next call to _update_scroll_bar (called via no_ut_refresh)'''
+        self._use_scroll_bar = use_scroll_bar
+        self._redraw_scroll_bar = True
+    
+    def get_use_scroll_bar(self):
+        '''Getter for self.use_scroll_bar'''
+        return self._use_scroll_bar
+    
+    use_scroll_bar = property(get_use_scroll_bar, set_use_scroll_bar)
+    
+    def _init_scroll_bar(self):
+        '''Initialize the scroll bar'''
+        if self.use_scroll_bar:
+            logging.debug("use_scroll_bar True -> init'ing")
+            self.window.addch(0, 0, curses.ACS_HLINE)
+            self.window.vline(1, 0, curses.ACS_VLINE, self.area.lines - 1)
+            self.window.vline(self.area.lines, 0, curses.ACS_HLINE,
+                              self.area.scrollable_lines - self.area.lines)
+            self.window.addch(self.area.scrollable_lines - 1, 0,
+                              curses.ACS_HLINE)
+        else:
+            logging.debug("use_scroll_bar False -> clearing")
+            self.window.vline(0, 0, InnerWindow.BKGD_CHAR,
+                              self.area.scrollable_lines)
+        self._redraw_scroll_bar = False
+    
+    def _update_scroll_bar(self):
+        '''Update the scroll bar after scrolling'''
+        if self._redraw_scroll_bar:
+            logging.debug("redraw scoll bar -> init'ing")
+            self._init_scroll_bar()
+        if self.use_scroll_bar:
+            logging.log(LOG_LEVEL_INPUT, "use_scroll_bar True -> updating")
+            self.window.vline(self.current_line + 1, 0, curses.ACS_VLINE,
+                              self.area.lines - 1)
+            if self.at_top():
+                char = curses.ACS_HLINE
+            else:
+                char = curses.ACS_UARROW
+            self.window.addch(self.current_line, 0, char)
+            if self.at_bottom():
+                char = curses.ACS_HLINE
+            else:
+                char = curses.ACS_DARROW
+            self.window.addch(self.current_line + self.area.lines, 0, char)
+    
+    def no_ut_refresh(self):
+        '''The refresh method for ScrollWindows updates the visible portion
+        of the pad
+        
+        '''
+        self._update_scroll_bar()
+        self.window.noutrefresh(self.current_line, 0, self.area.y_loc,
+                                self.area.x_loc, self.area.lower_right_y,
+                                self.area.lower_right_x)
+    
+    def scroll(self, lines=None, scroll_to=None):
+        '''Scroll the visible region downward by 'lines'. 'lines' may be
+        negative. Alternatively, scroll directly to 'scroll_to'
+        
+        '''
+        if scroll_to is not None:
+            self.current_line = scroll_to
+        elif lines is not None:
+            self.current_line += lines
+        else:
+            raise ValueError("Missing keyword arg (requires either 'lines'"
+                             " or 'scroll_to')")
+        if self.current_line > self.bottom - 1:
+            self.current_line = self.bottom - 1
+        self.current_line = max(0, self.current_line)
+        self.no_ut_refresh()
+    
+    def on_key_down(self, input_key):
+        '''Activate the next object, or, for pure text windows, simply
+        scroll down one line
+        
+        '''
+        if self.active_object is not None:
+            try:
+                self.activate_object(self.active_object + 1)
+                return None
+            except IndexError:
+                if self.at_bottom():
+                    return input_key
+                else:
+                    self.scroll(1)
+                    return None
+        else:
+            if self.at_bottom():
+                logging.log(LOG_LEVEL_INPUT,
+                            "Already at bottom, returning input")
+                return input_key
+            else:
+                self.scroll(1)
+        return None
+    
+    def on_key_up(self, input_key):
+        '''Activate the previous object, or, for pure text windows, simply
+        scroll up one line
+        
+        '''
+        if self.active_object is not None:
+            try:
+                self.activate_object(self.active_object - 1)
+                return None
+            except IndexError:
+                if self.at_top():
+                    return input_key
+                else:
+                    self.scroll(-1)
+                    return None
+        else:
+            if self.at_top():
+                logging.log(LOG_LEVEL_INPUT, "Already at top, returning input")
+                return input_key
+            else:
+                self.scroll(-1)
+                return None
+    
+    def at_bottom(self):
+        '''Returns True if this ScrollWindow can't scroll down any further'''
+        return self.current_line >= self.bottom - 1
+    
+    def at_top(self):
+        '''Returns True if this ScrollWindow can't scroll up any further'''
+        return self.current_line == 0
+    
+    def activate_object(self, index=0, loop=False):
+        '''Activate the given object, without forcing to the top'''
+        self.activate_object_force(index=index, loop=loop)
+    
+    def activate_object_force(self, index=0, loop=False, force_to_top=False):
+        '''Activate the given object, if it is in the visible region.
+        If it's not, scroll one line - if it is then in the visible region,
+        activate it, otherwise, do nothing.
+        
+        If force_to_top is True, scroll immediately to this object, placing
+        it as close to the top of the visible region as possible, and
+        activate it.
+        
+        '''
+        old_obj = self.get_active_object()
+        super(ScrollWindow, self).activate_object(index, loop=loop)
+        active_y_loc = self.get_active_object().area.y_loc
+        logging.debug("active_y_loc=%s, current_line=%s", active_y_loc,
+                      self.current_line)
+        if force_to_top:
+            logging.debug("scroll_to=active_y_loc")
+            self.scroll(scroll_to=active_y_loc)
+        elif active_y_loc < self.current_line:
+            self.scroll(-1)
+            if active_y_loc < self.current_line:
+                super(ScrollWindow, self).activate_object(old_obj)
+        elif (active_y_loc - self.current_line) > self.area.lines:
+            logging.debug("scroll to (down) %s",
+                          (active_y_loc - self.area.lines))
+            self.scroll(1)
+            if (active_y_loc - self.current_line) > self.area.lines:
+                super(ScrollWindow, self).activate_object(old_obj)
+        else:
+            logging.debug("not scrolling")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/summary.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,202 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Display a summary of the user's selections
+'''
+
+import curses
+import logging
+
+from osol_install.profile.disk_info import SliceInfo
+from osol_install.profile.network_info import NetworkInfo
+from osol_install.text_install import _
+from osol_install.text_install.action import Action
+from osol_install.text_install.base_screen import BaseScreen
+from osol_install.text_install.inner_window import InnerWindow
+from osol_install.text_install.window_area import WindowArea
+from osol_install.text_install.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.")
+    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
+        
+        '''
+        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 = InnerWindow.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.install_profile.system.locale is None:
+            self.install_profile.system.determine_locale()
+        lines.append(_("  Default language: %s") %
+                     self.install_profile.system.actual_lang)
+        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.install_profile.system.hostname)
+        nic = self.install_profile.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(_("    Gateway: %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.install_profile.users[0]
+        primary = self.install_profile.users[1]
+        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.install_profile.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 = "OpenSolaris"
+            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/osol_install/text_install/text_install.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,271 @@
+#!/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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Text / (n)Curses based UI for installing OpenSolaris
+'''
+
+import curses
+import logging
+import os
+import platform
+import signal
+import subprocess
+import sys
+import traceback
+from optparse import OptionParser
+
+import libbe
+from osol_install.liblogsvc import init_log
+from osol_install.profile.install_profile import InstallProfile
+from osol_install.text_install import _, \
+                                      LOG_LOCATION_FINAL, \
+                                      DEFAULT_LOG_LOCATION, \
+                                      DEFAULT_LOG_LEVEL, \
+                                      DEBUG_LOG_LEVEL, \
+                                      LOG_FORMAT, \
+                                      LOG_LEVEL_INPUT, \
+                                      LOG_NAME_INPUT
+from osol_install.text_install.base_screen import RebootException
+from osol_install.text_install.date_time import DateTimeScreen
+from osol_install.text_install.disk_selection import DiskScreen
+from osol_install.text_install.fdisk_partitions import FDiskPart
+from osol_install.text_install.help_screen import HelpScreen
+from osol_install.text_install.install_progress import InstallProgress
+from osol_install.text_install.install_status import InstallStatus
+from osol_install.text_install.log_viewer import LogViewer
+from osol_install.text_install.main_window import MainWindow
+from osol_install.text_install.network_nic_configure import NICConfigure
+from osol_install.text_install.network_nic_select import NICSelect
+from osol_install.text_install.network_type import NetworkTypeScreen
+from osol_install.text_install.partition_edit_screen import PartEditScreen
+from osol_install.text_install.screen_list import ScreenList
+from osol_install.text_install.summary import SummaryScreen
+from osol_install.text_install.timezone import TimeZone
+from osol_install.text_install.users import UserScreen
+from osol_install.text_install.welcome import WelcomeScreen
+
+
+def setup_curses():
+    '''Initialize the curses module'''
+    initscr = curses.initscr()
+    if curses.has_colors():
+        curses.start_color()
+    curses.noecho()
+    curses.cbreak()
+    curses.meta(1)
+    try:
+        curses.curs_set(0)
+    except curses.error:
+        pass
+    return initscr
+
+
+def cleanup_curses():
+    '''Return the console to a usable state'''
+    curses.echo()
+    curses.nocbreak()
+    curses.endwin()
+    os.system("/usr/bin/clear")
+
+
+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
+    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.addLevelName(LOG_LEVEL_INPUT, LOG_NAME_INPUT)
+    logging.info("**** START ****")
+
+
+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.append(NetworkTypeScreen(main_win))
+    result.append(NICSelect(main_win))
+    result.append(NICConfigure(main_win))
+    result.append(TimeZone(main_win, screen=TimeZone.REGIONS))
+    result.append(TimeZone(main_win, screen=TimeZone.LOCATIONS))
+    result.append(TimeZone(main_win))
+    result.append(DateTimeScreen(main_win))
+    result.append(UserScreen(main_win))
+    result.append(SummaryScreen(main_win))
+    result.append(InstallProgress(main_win))
+    result.append(InstallStatus(main_win))
+    result.append(LogViewer(main_win))
+    return result
+
+
+if __name__ == '__main__':
+    if os.getuid() != 0:
+        print _("The OpenSolaris Text Installer must be run with "
+                "root privileges")
+        sys.exit(1)
+    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:
+        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 logging service
+    INSTALL_PROFILE = None
+    try:
+        try:
+            INITSCR = setup_curses()
+            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)
+            INSTALL_PROFILE = InstallProfile()
+            INSTALL_PROFILE.log_location = OPTIONS.logname
+            INSTALL_PROFILE.log_final = LOG_LOCATION_FINAL
+            INSTALL_PROFILE.no_install_mode = OPTIONS.no_install
+            if platform.processor() == "i386":
+                INSTALL_PROFILE.is_x86 = True
+            else:
+                INSTALL_PROFILE.is_x86 = False
+            SCREEN_LIST = ScreenList()
+            MAIN_WIN = MainWindow(INITSCR, SCREEN_LIST,
+                                  force_bw=OPTIONS.force_bw)
+            SCREEN_LIST.help = HelpScreen(MAIN_WIN)
+            WIN_LIST = make_screen_list(MAIN_WIN)
+            SCREEN_LIST.screen_list = WIN_LIST 
+            SCREEN = SCREEN_LIST.get_next()
+            CTRL_C = None
+            while SCREEN is not None:
+                logging.debug("Install profile:\n%s", INSTALL_PROFILE)
+                logging.debug("Displaying screen: %s", type(SCREEN))
+                SCREEN = SCREEN.show(INSTALL_PROFILE)
+                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)
+            cleanup_curses()
+            ERRCODE = 0
+        finally:
+            cleanup_curses()
+    except RebootException:
+        if INSTALL_PROFILE.is_x86:
+            RET_VAL, BE_LIST = libbe.beList()
+            if RET_VAL == 0:
+                for be in BE_LIST:
+                    if be.get("active_boot", False):
+                        root_ds = be['root_ds']
+                        call_cmd = ["/usr/sbin/reboot", "-f", "--", root_ds]
+                        try:
+                            subprocess.call(call_cmd)
+                        except OSError, err:
+                            logging.warn("Fast reboot failed:\n\t'%s'\n%s",
+                                         " ".join(call_cmd), err)
+                        else:
+                            logging.warn("Fast reboot failed. Will attempt"
+                                         " standard reboot\n(Fast reboot "
+                                         "args:%s)", " ".join(call_cmd))
+                        break
+        # Fallback reboot. If the subprocess.call(..) command above fails,
+        # Simply do a standard reboot.
+        subprocess.call("/usr/sbin/reboot")
+    except SystemExit:
+        raise
+    except:
+        logging.error(str(INSTALL_PROFILE))
+        logging.error(traceback.format_exc())
+        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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/ti_install.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,665 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Installation engine for Text Installer
+'''
+
+import os
+import logging
+import commands
+import datetime
+import platform
+import shutil
+import subprocess as sp
+import osol_install.tgt as tgt
+from osol_install.libzoneinfo import tz_isvalid
+from libbe import beUnmount
+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 osol_install.install_utils import exec_cmd_outputs_to_log
+from osol_install.profile.disk_info import PartitionInfo
+from osol_install.profile.network_info import NetworkInfo
+import osol_install.text_install.ti_install_utils as ti_utils 
+
+#
+# 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"
+IPS_TRANSFER = "1" # Only used by the ict_set_user_role() ICT
+
+# The following 2 values, ICT_USER_UID and ICT_USER_GID are defined
+# in the ICT C APIs.  When those are ported to Python, these will
+# probably be defined there.
+ICT_USER_UID = "101"
+ICT_USER_GID = "10"
+
+INSTALL_FINISH_PROG = "/sbin/install-finish"
+
+# Initial BE name
+INIT_BE_NAME = "opensolaris"
+
+# definitions for ZFS pool
+INSTALL_SNAPSHOT = "install"
+
+INSTALLED_ROOT_DIR = "/a"
+X86_BOOT_ARCHIVE_PATH = "/.cdrom/platform/i86pc/%s/boot_archive"
+
+# 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
+
+
+SYSID_FILE = "/etc/.sysIDtool.state"
+SYSID_FILE_UMASK = 022
+SYSID_FILE_CONTENT = [["1", "# System previously configured?"],
+              ["1", "# Bootparams succeeded?"],
+              ["1", "# System is on a network?"],
+              ["1", "# Extended network information gathered?"],
+              ["1", "# Autobinder succeeded?"],
+              ["1", "# Network has subnets?"],
+              ["1", "# root password prompted for?"],
+              ["1", "# locale and term prompted for?"],
+              ["1", "# security policy in place"],
+              ["1", "# NFSv4 domain configured"],
+              # term type must be the last entry
+              ["sun", ""]]
+
+
+def create_sysid_file():
+    '''Create the /etc/.sysIDtool.state file'''
+    try:
+        with open(SYSID_FILE, "w") as sysid_file:
+            for entry in SYSID_FILE_CONTENT:
+                sysid_file.write(entry[0] + "\t" + entry[1] + "\n")
+  
+        # set the umask on the file
+        os.chmod(SYSID_FILE, SYSID_FILE_UMASK)
+    except IOError, ioe:
+        logging.error("Unable to write to %s", SYSID_FILE)
+        logging.exception(ioe)
+        raise ti_utils.InstallationError
+    except OSError, ose:
+        logging.error("Unable to create %s", SYSID_FILE)
+        logging.exception(ose)
+        raise ti_utils.InstallationError
+
+
+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 OpenSolaris installation"
+    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 = ()
+        for ds in reversed(ZFS_SHARED_FS): # must traverse it in reversed order
+            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)]
+
+    # if it is running on x86, need to unpack the root archive from
+    # the architecture that's not booted from.
+    if platform.processor() == "i386":
+        (status, inst_set) = commands.getstatusoutput("/bin/isainfo -k")
+        if (status != 0):
+            logging.error("Unable to determine instruction set.")
+            raise ti_utils.InstallationError
+
+        if (inst_set == "amd64"):
+            # Running 64 bit kernel, need to unpack 32 bit archive
+            tm_argslist.extend([(TM_UNPACK_ARCHIVE,
+                               X86_BOOT_ARCHIVE_PATH % "")])
+        else:
+            # Running 32 bit kernel, need to unpack 64 bit archive
+            tm_argslist.extend([(TM_UNPACK_ARCHIVE,
+                               X86_BOOT_ARCHIVE_PATH % "amd64")])
+
+    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.
+
+    '''
+    #
+    # The following information is needed for installation.
+    # Make sure they are provided before even starting
+    #
+
+    # locale
+    locale = install_profile.system.locale
+    logging.debug("default locale: %s", locale)
+
+    # timezone
+    timezone = install_profile.system.tz_timezone
+    logging.debug("time zone: %s", timezone)
+
+    # hostname
+    hostname = install_profile.system.hostname
+    logging.debug("hostname: %s", hostname)
+
+    ulogin = None 
+    user_home_dir = ""
+
+    root_user = install_profile.users[0]
+    root_pass = root_user.password
+
+    reg_user = install_profile.users[1]
+    ureal_name = reg_user.real_name
+    ulogin = reg_user.login_name
+    upass = reg_user.password
+
+    logging.debug("Root password: %s", root_pass)
+
+    if ulogin:
+        user_home_dir = "/export/home/" + ulogin
+        ZFS_SHARED_FS.insert(0, user_home_dir)
+        logging.debug("User real name: %s", ureal_name)
+        logging.debug("User login: %s", ulogin)
+        logging.debug("User password: %s", upass)
+
+    (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() + install_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")
+
+    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)
+
+    #
+    # The /etc/.sysIDtool.state file needs to be written before calling
+    # the ICTs, because it gets copied over by the ICTs into the installed
+    # system.
+    #
+    create_sysid_file()
+    
+    try:
+        run_ICTs(install_profile, hostname, ict_mesg, inst_device,
+                 locale, root_pass, ulogin, upass, ureal_name,
+                 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
+    # /, /opt, /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
+    for fs in ZFS_SHARED_FS:
+        exec_cmd(["/usr/sbin/zfs", "unmount", rootpool_name + fs],
+                 "unmount " + rootpool_name + fs)
+        exec_cmd(["/usr/sbin/zfs", "set", "mountpoint=" + fs,
+                 rootpool_name + fs], "change mount point for " +
+                 rootpool_name + fs)
+
+    # 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,
+             root_pass, ulogin, upass, ureal_name, 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
+
+    #
+    # create user directory if needed
+    #
+    try:
+        exec_cmd([ICT_PROG, "ict_configure_user_directory", INSTALLED_ROOT_DIR,
+                  ulogin], "execute ict_configure_user_directory() ICT")
+    except ti_utils.InstallationError:
+        failed_icts += 1
+
+    #
+    # set host name
+    #
+    try:
+        exec_cmd([ICT_PROG, "ict_set_host_node_name",
+                  INSTALLED_ROOT_DIR, hostname],
+                  "execute ict_set_host_node_name() ICT")
+    except ti_utils.InstallationError:
+        failed_icts += 1
+    
+    try:
+        exec_cmd([ICT_PROG, "ict_set_user_profile", INSTALLED_ROOT_DIR,
+                  ulogin], "execute ict_set_user_profile() 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
+
+    # Text installer installation does not use IPS to install files at
+    # this time.  However, unlike the GUI installer, text installer
+    # does not have root as a role.  Text installer
+    # runs as root, which is a user.  So, we need to use the IPS_TRANSFER
+    # mode of the ict_set_user_role ICT for the logic to
+    # set root as a role or not to act correctly.
+    try:
+        exec_cmd([ICT_PROG, "ict_set_user_role", INSTALLED_ROOT_DIR,
+                  IPS_TRANSFER, ulogin], "execute ict_set_user_role() 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, "-R", root_pass,
+           "-n", ureal_name, "-l", ulogin, "-p", upass, "-G", ICT_USER_GID,
+           "-U", ICT_USER_UID]
+    if (install_profile.nic.type == NetworkInfo.NONE):
+        cmd.append("-N")
+    
+    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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/ti_install_utils.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,428 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/timezone.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,239 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Time Zone selection screen - used for all three TimeZone screens
+'''
+
+import curses
+import logging
+
+from osol_install.libzoneinfo import get_tz_info, tz_isvalid
+from osol_install.profile.system_info import SystemInfo
+from osol_install.text_install import _, LOG_LEVEL_INPUT
+from osol_install.text_install.base_screen import BaseScreen, SkipException
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.scroll_window import ScrollWindow
+from osol_install.text_install.window_area import WindowArea
+
+
+class TimeZone(BaseScreen):
+    '''Allow user to select timezone based on already selected
+    continent and country.
+    
+    '''
+    
+    UTC_TEXT = _("UTC/GMT")
+    SCROLL_SIZE = 2
+    BORDER_WIDTH = (0, 3)
+    REGIONS = "regions"
+    LOCATIONS = "locations"
+    TIMEZONE = "timezone"
+    
+    def __init__(self, main_win, screen=None):
+        super(TimeZone, self).__init__(main_win)
+        self.sys_info = None
+        if screen is None:
+            self.screen = TimeZone.TIMEZONE
+        else:
+            self.screen = screen
+        self.tz_tuples = None
+        self.tz_list = None
+        self.cur_timezone_idx = 0
+        self.cur_timezone_parent = None
+        self.last_timezone_parent = None
+        self.cur_continent = None
+        self.cur_country = None
+        self.scroll_region = None
+        self.last_country = None
+        self.last_continent = None
+        if self.screen == TimeZone.TIMEZONE:
+            self.header_text = _("Time Zone")
+            self.intro = _("Select your time zone.")
+            self.title = _("Time Zones")
+        elif self.screen == TimeZone.LOCATIONS:
+            self.header_text = _("Time Zone: Locations")
+            self.intro = _("Select the location that contains your time zone.")
+            self.title = _("Locations")
+        else:
+            self.header_text = _("Time Zone: Regions")
+            self.intro = _("Select the region that contains your time zone.")
+            self.title = _("Regions")
+    
+    def _show(self):
+        '''Create the list of time zones'''
+        logging.debug("self.screen %s", self.screen)
+        
+        if self.install_profile.system is None:
+            self.install_profile.system = SystemInfo()
+        self.sys_info = self.install_profile.system
+        
+        self.cur_country = self.sys_info.tz_country
+        self.cur_continent = self.sys_info.tz_region
+        
+        if self.cur_continent == SystemInfo.UTC and self.screen != "regions":
+            raise SkipException
+        
+        self.center_win.border_size = TimeZone.BORDER_WIDTH
+        
+        if self.screen == TimeZone.LOCATIONS:
+            self.cur_timezone_parent = self.cur_continent
+        elif self.screen == TimeZone.TIMEZONE:
+            self.cur_timezone_parent = self.cur_country
+        
+        logging.debug("cur_continent %s, cur_country %s",
+                      self.cur_continent, self.cur_country)
+        
+        y_loc = 1
+        
+        y_loc += self.center_win.add_paragraph(self.intro, y_loc)
+        
+        y_loc += 1
+        menu_item_max_width =  self.win_size_x - TimeZone.SCROLL_SIZE
+        self.center_win.add_text(self.title, y_loc, TimeZone.SCROLL_SIZE)
+        y_loc += 1
+        self.center_win.window.hline(y_loc, 3, curses.ACS_HLINE, 40)
+        
+        y_loc += 1
+        
+        
+        tz_list = self.get_timezones(self.cur_continent, self.cur_country)
+        
+        area = WindowArea(x_loc=0, y_loc=y_loc,
+                          scrollable_lines=len(tz_list)+1)
+        area.lines = self.win_size_y - (y_loc + 1)
+        area.columns = self.win_size_x
+        logging.debug("area.lines=%d, area.columns=%d",
+                      area.lines, area.columns)
+        self.scroll_region = ScrollWindow(area, window=self.center_win)
+        
+        utc = 0
+        if self.screen == TimeZone.REGIONS:
+            utc_area = WindowArea(1, len(TimeZone.UTC_TEXT) + 1, 0,
+                                  TimeZone.SCROLL_SIZE)
+            utc_item = ListItem(utc_area, window=self.scroll_region,
+                                text=TimeZone.UTC_TEXT,
+                                data_obj=SystemInfo.UTC)
+            utc = 1
+        
+        # add the entries to the screen
+        for idx, timezone in enumerate(tz_list):
+            logging.log(LOG_LEVEL_INPUT, "tz idx = %i name= %s",
+                        idx, tz_list[idx])
+            hilite = min(menu_item_max_width, len(timezone) + 1)
+            win_area = WindowArea(1, hilite, idx+utc, TimeZone.SCROLL_SIZE)
+            list_item = ListItem(win_area, window=self.scroll_region,
+                                 text=timezone, data_obj=timezone)
+            y_loc += 1
+        
+        self.main_win.do_update()
+        self.center_win.activate_object(self.scroll_region)
+        logging.debug("self.cur_timezone_idx=%s", self.cur_timezone_idx)
+        self.scroll_region.activate_object_force(self.cur_timezone_idx,
+                                                 force_to_top=True)
+    
+    def get_timezones(self, continent, country_code):
+        '''Get the timezone info, a list of tuples, each with:
+            [0] timezone name
+            [1] timezone name descriptive
+            [2] localized timezone name
+        '''
+        
+        logging.debug("get_timezones continent=%s", continent)
+        logging.debug("get_timezones country_code=%s", country_code)
+        logging.debug("get_timezones self.cur_timezone_parent=%s,"
+                      " self.last_timezone_parent=%s",
+                      self.cur_timezone_parent, self.last_timezone_parent)
+
+        if (self.tz_list is None or self.cur_timezone_parent !=
+            self.last_timezone_parent):
+            self.tz_list = []
+            self.cur_timezone_idx = 0
+            
+            # pass get_tz_info the correct parameters:
+            #   none - to get regions/continents
+            #   continent  ("America") - to get countries
+            #   continent and country code ("America", "US")  - to get the 
+            #      timezones
+            if self.screen == TimeZone.REGIONS:
+                self.tz_tuples = get_tz_info()
+            elif self.screen == TimeZone.LOCATIONS:
+                self.tz_tuples = get_tz_info(continent)
+            else:
+                self.tz_tuples = get_tz_info(continent, country_code)
+            
+            # get name to display. First choice is localized name, then
+            # descriptive name, then plain name
+            logging.debug("number of timezones=%i", len(self.tz_tuples))
+            for item in self.tz_tuples:
+                if item[2]:
+                    logging.debug("tz2 = %s", item[2])
+                    self.tz_list.append(item[2])
+                elif item[1]:
+                    logging.debug("tz1 = %s", item[1])
+                    self.tz_list.append(item[1])
+                else:
+                    logging.debug("tz0 = %s", item[0])
+                    self.tz_list.append(item[0])
+
+        return self.tz_list
+
+
+    def on_change_screen(self):
+        '''Save the chosen timezone's index and name when leaving the screen'''
+        self.cur_timezone_idx = self.scroll_region.active_object
+        idx = self.cur_timezone_idx
+        self.last_timezone_parent = self.cur_timezone_parent
+        if self.screen == TimeZone.REGIONS:
+            if (self.scroll_region.get_active_object().data_obj ==
+                SystemInfo.UTC):
+                self.sys_info.tz_region_idx = 0
+                self.sys_info.tz_region = SystemInfo.UTC
+                self.sys_info.tz_country = SystemInfo.UTC
+                self.sys_info.tz_timezone = SystemInfo.UTC
+                self.sys_info.tz_display_name = TimeZone.UTC_TEXT
+            else:
+                self.sys_info.tz_region_idx = idx
+                self.sys_info.tz_region = self.tz_tuples[idx-1][0]
+            logging.debug("on_change_screen sys_info.tz_region: %s",
+                          self.sys_info.tz_region)
+        elif self.screen == TimeZone.LOCATIONS:
+            self.sys_info.tz_country_idx = idx
+            self.sys_info.tz_country = self.tz_tuples[idx][0]
+            self.last_continent = self.cur_continent
+            logging.debug("on_change_screen sys_info.tz_country: %s",
+                          self.sys_info.tz_country)
+            logging.debug("on_change_screen sys_info.tz_country_idx: %s",
+                          self.sys_info.tz_country_idx)
+        else:
+            self.sys_info.tz_timezone_idx = idx
+            self.sys_info.tz_timezone = self.tz_tuples[idx][0]
+            selected_tz = self.scroll_region.get_active_object().data_obj
+            self.sys_info.tz_display_name = selected_tz
+            self.last_country = self.cur_country
+            self.cur_timezone_idx = self.scroll_region.active_object
+            logging.debug("on_change_screen self.sys_info.tz_timezone: %s",
+                          self.sys_info.tz_timezone)
+            logging.debug("on_change_screen self.sys_info.tz_timezone_idx:%s",
+                          self.sys_info.tz_timezone_idx)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/users.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,295 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Set root password and primary user data
+'''
+
+import logging
+
+from osol_install.profile.user_info import UserInfo
+from osol_install.text_install import _
+from osol_install.text_install.base_screen import BaseScreen, UIMessage
+from osol_install.text_install.edit_field import EditField
+from osol_install.text_install.error_window import ErrorWindow
+from osol_install.text_install.list_item import ListItem
+from osol_install.text_install.window_area import WindowArea
+
+
+class UserScreen(BaseScreen):
+    '''Allow user to set:
+    - root password
+    - user real name
+    - user login
+    - user password
+    
+    '''
+    
+    HEADER_TEXT = _("Users")
+    INTRO = _("Define a root password for the system and user account for"
+              " yourself.")
+    ROOT_TEXT = _("System Root Password")
+    ROOT_LABEL = _("Root password:")
+    CONFIRM_LABEL = _("Confirm password:")
+    USER_TEXT = _("Create a user account")
+    NAME_LABEL = _("Your real name:")
+    USERNAME_LABEL = _("Username:")
+    USER_PASS_LABEL = _("User password:")
+    
+    NO_ROOT_HEADER = _("No Root Password")
+    NO_ROOT_TEXT = _("A root password has not been defined. The system is "
+                     "completely unsecured.\nChoose Cancel to set a "
+                     "root password.")
+    CONTINUE_BTN = _("Continue")
+    CANCEL_BTN = _("Cancel")
+    
+    MAX_PASS_LEN = 16
+    ITEM_OFFSET = 2
+    
+    def __init__(self, main_win):
+        super(UserScreen, self).__init__(main_win)
+        self.max_text_len = (self.win_size_x - UserScreen.MAX_PASS_LEN -
+                             UserScreen.ITEM_OFFSET) / 2
+        max_field = max(len(UserScreen.ROOT_LABEL),
+                        len(UserScreen.CONFIRM_LABEL),
+                        len(UserScreen.NAME_LABEL),
+                        len(UserScreen.USERNAME_LABEL),
+                        len(UserScreen.USER_PASS_LABEL))
+        self.text_len = min(max_field + 1, self.max_text_len)
+        self.list_area = WindowArea(1, self.text_len, 0,
+                                    UserScreen.ITEM_OFFSET)
+        self.edit_area = WindowArea(1, UserScreen.MAX_PASS_LEN + 1,
+                                    0, self.text_len)
+        err_x_loc = 2 * self.max_text_len - self.text_len
+        err_width = (self.text_len + UserScreen.MAX_PASS_LEN)
+        self.error_area = WindowArea(1, err_width, 0, err_x_loc)
+        self.root = None
+        self.user = None
+        self.root_pass_list = None
+        self.root_pass_edit = None
+        self.root_pass_err = None
+        self.root_confirm_list = None
+        self.root_confirm_edit = None
+        self.real_name_list = None
+        self.real_name_edit = None
+        self.username_err = None
+        self.username_list = None
+        self.username_edit = None
+        self.user_pass_err = None
+        self.user_pass_list = None
+        self.user_pass_edit = None
+        self.user_confirm_list = None
+        self.user_confirm_edit = None
+    
+    def _show(self):
+        '''Display the user name, real name, and password fields'''
+        if len(self.install_profile.users) != 2:
+            root = UserInfo()
+            root.login_name = "root"
+            root.is_role = True
+            user = UserInfo()
+            self.install_profile.users = [root, user]
+        self.root = self.install_profile.users[0]
+        self.user = self.install_profile.users[1]
+        
+        logging.debug("Root: %s", self.root)
+        logging.debug("User: %s", self.user)
+        
+        y_loc = 1
+        
+        self.center_win.add_paragraph(UserScreen.INTRO, y_loc, 1, y_loc + 2,
+                                      self.win_size_x - 1)
+        
+        y_loc += 3
+        self.center_win.add_text(UserScreen.ROOT_TEXT, y_loc, 1,
+                                 self.win_size_x - 1)
+        
+        y_loc += 2
+        self.list_area.y_loc = y_loc
+        self.root_pass_list = ListItem(self.list_area, window=self.center_win,
+                                       text=UserScreen.ROOT_LABEL)
+        self.root_pass_edit = EditField(self.edit_area,
+                                        window=self.root_pass_list,
+                                        masked=True,
+                                        text=("*" * self.root.passlen))
+        self.root_pass_edit.clear_on_enter = True
+        
+        y_loc += 1
+        self.error_area.y_loc = y_loc
+        self.list_area.y_loc = y_loc
+        self.root_pass_err = ErrorWindow(self.error_area,
+                                         window=self.center_win)
+        self.root_confirm_list = ListItem(self.list_area,
+                                          window=self.center_win,
+                                          text=UserScreen.CONFIRM_LABEL)
+        self.root_confirm_edit = EditField(self.edit_area,
+                                           window=self.root_confirm_list,
+                                           masked=True,
+                                           text=("*" * self.root.passlen),
+                                           on_exit=pass_match,
+                                           error_win=self.root_pass_err)
+        self.root_confirm_edit.clear_on_enter = True
+        rc_edit_kwargs = {"linked_win" : self.root_pass_edit}
+        self.root_confirm_edit.on_exit_kwargs = rc_edit_kwargs
+        
+        y_loc += 2
+        self.center_win.add_text(UserScreen.USER_TEXT, y_loc, 1,
+                                 self.win_size_x - 1)
+        
+        y_loc += 2
+        self.list_area.y_loc = y_loc
+        self.real_name_list = ListItem(self.list_area, window=self.center_win,
+                                       text=UserScreen.NAME_LABEL)
+        self.real_name_edit = EditField(self.edit_area,
+                                        window=self.real_name_list,
+                                        text=self.user.real_name)
+        
+        y_loc += 1
+        self.list_area.y_loc = y_loc
+        self.error_area.y_loc = y_loc
+        self.username_err = ErrorWindow(self.error_area,
+                                        window=self.center_win)
+        self.username_list = ListItem(self.list_area,
+                                      window=self.center_win,
+                                      text=UserScreen.USERNAME_LABEL)
+        self.username_edit = EditField(self.edit_area,
+                                       window=self.username_list,
+                                       validate=username_valid_alphanum,
+                                       error_win=self.username_err,
+                                       on_exit=username_valid,
+                                       text=self.user.login_name)
+        
+        y_loc += 1
+        self.list_area.y_loc = y_loc
+        self.error_area.y_loc = y_loc
+        self.user_pass_err = ErrorWindow(self.error_area,
+                                         window=self.center_win)
+        self.user_pass_list = ListItem(self.list_area, window=self.center_win,
+                                       text=UserScreen.USER_PASS_LABEL)
+        self.user_pass_edit = EditField(self.edit_area,
+                                        window=self.user_pass_list,
+                                        masked=True,
+                                        text=("*" * self.user.passlen))
+        self.user_pass_edit.clear_on_enter = True
+        
+        y_loc += 1
+        self.list_area.y_loc = y_loc
+        self.user_confirm_list = ListItem(self.list_area,
+                                          window=self.center_win,
+                                          text=UserScreen.CONFIRM_LABEL)
+        self.user_confirm_edit = EditField(self.edit_area,
+                                           window=self.user_confirm_list,
+                                           masked=True, on_exit=pass_match,
+                                           error_win=self.user_pass_err,
+                                           text=("*" * self.user.passlen))
+        self.user_confirm_edit.clear_on_enter = True
+        uc_edit_kwargs = {"linked_win" : self.user_pass_edit}
+        self.user_confirm_edit.on_exit_kwargs = uc_edit_kwargs
+        
+        self.main_win.do_update()
+        self.center_win.activate_object(self.root_pass_list)
+    
+    def on_change_screen(self):
+        '''Save real name and login name always'''
+        self.user.real_name = self.real_name_edit.get_text()
+        self.user.login_name = self.username_edit.get_text()
+        self.root.is_role = bool(self.user.login_name)
+        
+        if self.root_pass_edit.get_text() != self.root_confirm_edit.get_text():
+            self.root.password = ""
+        else:
+            self.root.password = self.root_pass_edit.get_text()
+        self.root_pass_edit.clear_text()
+        self.root_confirm_edit.clear_text()
+        
+        if self.user_pass_edit.get_text() != self.user_confirm_edit.get_text():
+            self.user.password = ""
+        else:
+            self.user.password = self.user_pass_edit.get_text()
+        self.user_pass_edit.clear_text()
+        self.user_confirm_edit.clear_text()
+    
+    def validate(self):
+        '''Check for mismatched passwords, bad login names, etc.'''
+        if self.root_pass_edit.get_text() != self.root_confirm_edit.get_text():
+            raise UIMessage, _("Root passwords don't match")
+        user_pass = self.user_pass_edit.get_text()
+        if user_pass != self.user_confirm_edit.get_text():
+            raise UIMessage, _("User passwords don't match")
+        login_name = self.username_edit.get_text()
+        logging.debug("login_name=%s", login_name)
+        username_valid(self.username_edit)
+        real_name = self.real_name_edit.get_text()
+        
+        logging.debug("real_name=%s", real_name)
+        # If password or real_name has been entered, require a login name
+        
+        if not login_name:
+            if real_name or user_pass:
+                raise UIMessage, _("Enter username or clear all user "
+                                    "account fields")
+        if not self.root_pass_edit.get_text():
+            color = self.main_win.theme.header
+            continue_anyway = self.main_win.pop_up(UserScreen.NO_ROOT_HEADER,
+                                                   UserScreen.NO_ROOT_TEXT,
+                                                   BaseScreen.CANCEL_BUTTON,
+                                                   UserScreen.CONTINUE_BTN,
+                                                   color=color)
+            if not continue_anyway:
+                raise UIMessage()
+
+
+def username_valid_alphanum(edit_field):
+    '''Ensure username is alphanumeric, and does not start with a digit'''
+    user_str = edit_field.get_text()
+    if not user_str:
+        return True
+    if user_str[0].isalpha():
+        if user_str.isalnum():
+            return True
+        else:
+            raise UIMessage, _("Username must be alphanumeric")
+    else:
+        raise UIMessage, _("First character must be a-zA-Z")
+
+
+def username_valid(edit_field):
+    '''Ensure the username is not "root" or "jack"'''
+    user_str = edit_field.get_text()
+    if user_str == "root":
+        raise UIMessage, _("'root' cannot be used")
+    elif user_str == "jack": 
+        raise UIMessage, _("'jack' cannot be used")
+    return True
+
+
+def pass_match(edit_field, linked_win=None):
+    '''Make sure passwords match'''
+    confirm_pass = edit_field.get_text()
+    if linked_win is None or linked_win.get_text() == confirm_pass:
+        return True
+    else:
+        edit_field.clear_text()
+        linked_win.clear_text()
+        raise UIMessage, _("Passwords don't match")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/welcome.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,74 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Contains the Welcome Screen for the Text Installer
+'''
+
+from osol_install.text_install import _
+from osol_install.text_install.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 OpenSolaris")
+    WELCOME_TEXT = _("Thanks for choosing to install OpenSolaris! This "
+                     "installer enables you to install the OpenSolaris "
+                     "Operating System (OS) on SPARC or x86 systems.\n\n"
+                     "For detailed step-by-step procedures for completing "
+                     "this installation, refer to the \"Getting Started "
+                     "Guide\" at opensolaris.com/use.\n\n"
+                     "The installation log will be at %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 = "- "
+    
+    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_profile.log_location
+        y_loc = 1
+        y_loc += self.center_win.add_paragraph(WelcomeScreen.WELCOME_TEXT %
+                                               log_file,
+                                               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/osol_install/text_install/window_area.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,76 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+'''
+Class for specifying an area of the screen (essentially, a glorified rectangle)
+'''
+
+class WindowArea(object):
+    '''Small class to describe an curses window area'''
+    
+    def __init__(self, lines=None, columns=None, y_loc=None, x_loc=None,
+                 scrollable_lines=None):
+        '''Attributes:
+        lines -> height
+        columns -> width
+        y_loc -> START y location
+        x_loc -> START x location
+        scrollable_lines -> Size of the scrollable area of this WindowArea.
+            This attribute is only relevant for ScrollWindows
+        
+        '''
+        self.lines = lines
+        self.columns = columns
+        self.y_loc = y_loc
+        self.x_loc = x_loc
+        self.scrollable_lines = scrollable_lines
+    
+    def __str__(self):
+        result = ("lines=%s, columns=%s, y_loc=%s, x_loc=%s, "
+                  "scrollable_lines=%s")
+        return result % (self.lines, self.columns, self.y_loc, self.x_loc,
+                         self.scrollable_lines)
+    
+    def relative_to_absolute(self, window, border=(0, 0)):
+        '''Translate coordinates from window relative to absolute
+        
+        This function will translate coordinates from being relative to
+        the passed in curses.window, to being absolute coordinates (based
+        against the entire terminal)
+        
+        '''
+        start_coords = window.getbegyx()
+        self.y_loc += start_coords[0] + border[0]
+        self.x_loc += start_coords[1] + border[1]
+    
+    def absolute_to_relative(self, window):
+        '''Translate coordinates from absolute to window relative
+        
+        This function translates absolute coordinates (based on entire
+        terminal) to coordinates relative to the passed in window.
+        
+        '''
+        start_coords = window.getbegyx()
+        self.y_loc -= start_coords[0]
+        self.x_loc -= start_coords[1]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/svc/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,69 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include $(SRC)/cmd/Makefile.cmd
+
+all:=		TARGET= all
+clean:=		TARGET= clean
+clobber:=	TARGET= clobber
+install:=	TARGET= install
+
+PROG_KSH=	text-mode-menu.ksh
+PROG=		$(PROG_KSH:%.ksh=%)
+
+MSG_DOMAIN=	SUNW_INSTALL_TEXT_MENU
+POFILE=		$(MSG_DOMAIN).po
+
+ROOTPROGS=      $(PROG:%=$(ROOTUSRSBIN)/%)
+ROOTMSGS=	$(POFILE:%=$(ROOTUSRLIBMSGS)/%)
+
+SYSMANIFESTSRC= text-mode-menu.xml
+SYSMANIFESTS= $(SYSMANIFESTSRC:%=$(ROOTMANSYS)/%)
+
+.KEEP_STATE:
+
+all:	$(PROG) $(POFILE)
+
+clean:
+	rm -f $(ROOTPROGS) $(ROOTMSGS) $(SYSMANIFESTS)
+
+clobber: clean
+
+install: all .WAIT $(ROOTPROGS) $(ROOTMSGS) \
+	 $(ROOTMANSYS) $(ROOTLIBSVCMETHOD) $(SYSMANIFESTS)
+
+$(PROG):	$(PROG_KSH)
+	cp $(PROG_KSH) $(PROG)
+
+msgs:	$(POFILE)
+
+$(POFILE):	$(PROG_KSH)
+	@echo "Making messages file $(POFILE)"
+	@$(ROOTADMINBIN)/xgetsh -d $(MSG_DOMAIN) $(PROG_KSH)
+
+FRC:
+
+include $(SRC)/cmd/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/svc/text-mode-menu.ksh	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,219 @@
+#!/bin/ksh93
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+exec </dev/console >/dev/console 2>&1
+
+LANGUAGE_FILE=/etc/sysconfig/language
+
+export TEXTDOMAIN="SUNW_INSTALL_TEXT_MENU"
+# LOGNAME variable is needed to display the shell prompt appropriately
+export LOGNAME=`/usr/bin/logname`
+
+# Block all signals which could terminate the menu or return to a parent process
+trap "" TSTP INT TERM ABRT QUIT
+
+# Determine which shell program to use by grabbing this user's login-shell
+# from /etc/passwd
+ROOT_SHELL=$(/usr/bin/getent passwd $LOGNAME | \
+    /usr/xpg4/bin/awk -F : '{print $7}')
+
+# On the off chance that $LOGNAME has no shell (default grabbed from passwd(4))
+if [[ -z "$ROOT_SHELL" ]]; then
+	ROOT_SHELL="/usr/bin/sh"
+fi
+
+# Define the menu of commands and prompts
+menu_items=( \
+    (menu_str=`gettext "Install OpenSolaris"`				 \
+	cmds=("/usr/bin/text-install")					 \
+	do_subprocess="true"						 \
+	msg_str="")							 \
+    (menu_str=`gettext "Shell"`						 \
+	cmds=("$ROOT_SHELL")						 \
+	do_subprocess="true"						 \
+	msg_str=`gettext "To return to the main menu, exit the shell"`)	 \
+    # this string gets overwritten every time $TERM is updated
+    (menu_str=`gettext "Terminal type (currently "`"$TERM)"		 \
+	cmds=("prompt_for_term_type")					 \
+	do_subprocess="false"						 \
+	msg_str="")							 \
+    (menu_str=`gettext "Reboot"`					 \
+	cmds=("/usr/sbin/reboot" "/usr/bin/sleep 10000")		 \
+	do_subprocess="true"						 \
+	msg_str="")							 \
+)
+
+# Update the menu_str for the terminal type
+# entry. Every time the terminal type has been
+# updated, this function must be called.
+function update_term_menu_str
+{
+    # update the menu string to reflect the current TERM
+    for i in "${!menu_items[@]}"; do
+	    if [[ "${menu_items[$i].cmds[0]}" = "prompt_for_term_type" ]] ; then
+		menu_items[$i].menu_str=`gettext "Terminal type (currently "`"$TERM)"
+	    fi
+    done
+}
+
+# Set the TERM variable as follows:
+#
+# If connected to SPARC via keyboard/monitor, set TERM to "sun"
+# If connected to X86 via keyboard/monitor, set TERM to "sun-color"
+# If running on serial console, set TERM to "xterm"
+#
+function set_term_type
+{
+    export TERM=xterm
+    arch=`/usr/bin/uname -p`
+    if [[ "${arch}" = "sparc" ]] ; then
+	output_device=`/usr/sbin/prtconf -vp | 			\
+		/usr/bin/grep "output-device" | 		\
+		/usr/bin/cut -f 2 -d\'`
+	[[ "$output_device" = "screen" ]] && export TERM=sun
+    else
+	console=`/usr/sbin/prtconf -vp | 			\
+		/usr/bin/grep "console" |			\
+		/usr/bin/cut -f 2 -d\'`
+	[[ -z ${console} ]] && export TERM=sun-color
+    fi
+    update_term_menu_str
+}
+
+# Prompt the user for terminal type
+function prompt_for_term_type
+{
+	integer i
+
+	# list of suggested termtypes
+	typeset termtypes=(
+		typeset -a fixedlist
+		integer list_len        # number of terminal types
+	)
+
+	# hard coded common terminal types
+	termtypes.fixedlist=(
+		[0]=(  name="dtterm"		desc="CDE terminal emulator")
+		[1]=(  name="xterm"		desc="xterm"		    )
+		[2]=(  name="vt100"		desc="DEC VT100"	    )
+	)
+
+	termtypes.list_len=${#termtypes.fixedlist[@]}
+
+	# Start with a newline before presenting the choices
+	print
+	printf "Indicate the type of terminal being used, such as:\n"
+
+	# list suggested terminal types
+	for (( i=0 ; i < termtypes.list_len ; i++ )) ; do
+		nameref node=termtypes.fixedlist[$i]
+		printf "  %-10s %s\n" "${node.name}" "${node.desc}"
+	done
+
+	print
+	# Prompt user to select terminal type and check for valid entry
+	typeset term=""
+	while true ; do
+		read "term?Enter terminal type [$TERM]: " || continue
+
+		# if the user just hit return, don't set the term variable
+		[[ "${term}" = "" ]] && return
+			
+		# check if the user specified option is valid
+		term_entry=`/usr/bin/ls /usr/gnu/share/terminfo/*/$term 2> /dev/null`
+		[[ ! -z ${term_entry} ]] && break
+		printf "%s `gettext \"terminal type not supported. Supported terminal types can be\"` \n" "${term}"
+		printf "`gettext \"found by using the Shell to list the contents of /usr/gnu/share/terminfo.\"`\n\n"
+	done
+
+	export TERM="${term}"
+	update_term_menu_str
+}
+
+set_term_type
+
+# Set LANG to the language specified in /etc/sysconfig/language
+if [ -f ${LANGUAGE_FILE} ] ; then
+    language=`grep RC_LANG ${LANGUAGE_FILE} | cut -d '=' -f 2`
+    if [ ! -z ${language} ] ; then
+	export LANG=$language
+    fi
+fi
+
+# default to the Installer option
+defaultchoice=1
+
+for ((;;)) ; do
+
+	# Display the menu.
+	clear
+	printf \
+	    "`gettext 'Welcome to the OpenSolaris %s installation menu'` \n\n" \
+	    "`uname -v`"
+	for i in "${!menu_items[@]}"; do
+		print "\t$((${i} + 1))  ${menu_items[$i].menu_str}"
+	done
+
+	# Take an entry (by number). If multiple numbers are
+ 	# entered, accept only the first one.
+	input=""
+	dummy=""
+	print -n "\n`gettext 'Please enter a number '`""[${defaultchoice}]: "
+	read input dummy 2>/dev/null
+
+	# If no input was supplied, select the default option
+	[[ -z ${input} ]] && input=$defaultchoice
+
+	# First char must be a digit.
+	if [[ ${input} =~ [^1-9] || ${input} > ${#menu_items[@]} ]] ; then
+		continue
+	fi
+
+	# Reorient to a zero base.
+	input=$((${input} - 1))
+
+	nameref msg_str=menu_items[$input].msg_str
+
+	# Launch commands as a subprocess.
+	# However, launch the functions within the context 
+	# of the current process.
+	if [[ "${!menu_items[$input].do_subprocess}" = "true" ]] ; then
+		(
+		trap - TSTP INT TERM ABRT QUIT
+		# Print out a message if requested
+		[[ ! -z "${msg_str}" ]] && printf "%s\n" "${msg_str}"
+		for j in "${!menu_items[$input].cmds[@]}"; do
+			${menu_items[${input}].cmds[$j]}
+		done
+		)
+	else
+		# Print out a message if requested
+		[[ ! -z "${msg_str}" ]] && printf "%s\n" "${msg_str}"
+		for j in "${!menu_items[$input].cmds[@]}"; do
+			${menu_items[${input}].cmds[$j]}
+		done
+	fi
+done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/svc/text-mode-menu.xml	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,93 @@
+<?xml version="1.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 2010 Sun Microsystems, Inc.  All rights reserved.
+ Use is subject to license terms.
+
+ NOTE:  This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade.  Make customizations in a different
+ file.
+-->
+
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+
+<service_bundle type='manifest' name='SUNWtextinstall:text-mode-menu'>
+
+<!-- system/install-setup is used as the service name
+     since it's an SMF endpoint.
+-->
+
+<service
+	name='system/install-setup'
+	type='service'
+	version='1'>
+
+	<create_default_instance enabled='true' />
+	<single_instance/>
+
+	<!-- Must be able to access /tmp. -->
+	<dependency
+		name='single-user'
+		grouping='require_all'
+		restart_on='none'
+		type='service'>
+		<service_fmri value='svc:/milestone/single-user' />
+	</dependency>
+
+	<method_context>
+		<method_credential user='root' group='root'/>
+	</method_context>
+
+	<exec_method
+		type='method'
+		name='start'
+		exec='/usr/sbin/text-mode-menu'
+		timeout_seconds='0' />
+
+	<exec_method
+		type='method'
+		name='stop'
+		exec=':kill -9'
+		timeout_seconds='3' />
+
+	<property_group name='startd' type='framework'>
+		<!-- duration is "child" because this allows the main menu to
+		     die (along with child process) and be restarted any number
+		     of times.  Both transient and contract duration lock up 
+		     system when only menu is killed.
+		-->
+		<propval name='duration' type='astring' value='child' />
+		<propval name='need_session' type='boolean' value='true' />
+		<propval name='ignore_error' type='astring' value='core,signal' />
+	</property_group>
+
+	<stability value='Unstable' />
+
+	<template>
+		<common_name>
+			<loctext xml:lang='C'>
+				text mode menu
+			</loctext>
+		</common_name>
+	</template>
+</service>
+</service_bundle>
--- a/usr/src/lib/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -26,22 +26,24 @@
 
 include $(SRC)/Makefile.master
 
-SUBDIRS=	libaiscf \
+SUBDIRS=	install_utils \
+		libaiscf \
 		libaiscf_pymod \
 		libbe \
 		libbe_pymod \
+		libict  \
+		libict_pymod \
 		liblogsvc \
 		liblogsvc_pymod \
-		liborchestrator	\
-		libict	\
+		liborchestrator \
 		libspmicommon \
+		libtarget_pymod \
 		libtd \
 		libti \
 		libti_pymod \
 		libtransfer \
 		libtransfer_pymod \
-		libict_pymod \
-		install_utils
+		libzoneinfo_pymod
 
 HDRSUBDIRS=	libadmldb libadmutil
 
@@ -86,6 +88,7 @@
 libti:			liblogsvc libbe
 libtransfer:		liblogsvc
 libict_pymod:		liblogsvc
+libtarget_pymod:	libtd libti
 
 
 $(ROOTADMINLIBLINKS):
--- a/usr/src/lib/libict/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libict/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # Target Discovery software library makefile
@@ -52,9 +52,13 @@
 LINTFILES	= ${SRCS:%.c=${ARCH}/%.ln}
 LINTFLAGS	= -uaxm ${CPPFLAGS}
 
+TEST_PROGS	= ict_test
+ROOT_TEST_PROGS	= $(TEST_PROGS:%=$(ROOTOPTINSTALLTESTBIN)/%)
+CLEANFILES	= $(TEST_PROGS) ict_test.o
+
 .KEEP_STATE:
 
-all: $(HDRS) .WAIT dynamic
+all: $(HDRS) .WAIT dynamic $(TEST_PROGS)
 	@true
 
 #Install Completion Tasks test program
@@ -67,7 +71,7 @@
 
 install:	all .WAIT \
 		$(ROOTADMINLIB) $(ROOTADMINLIBS) $(ROOTADMINLIBDYNLIB) \
-		$(ROOTADMINLIBDYNLIBLINK)
+		$(ROOTADMINLIBDYNLIBLINK) $(ROOT_TEST_PROGS)
 
 install_test:	all .WAIT \
 		$(ROOTADMINLIB) $(ROOTADMINLIBS) $(ROOTADMINLIBDYNLIB) \
--- a/usr/src/lib/libict_pymod/ict.py	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libict_pymod/ict.py	Tue Mar 16 14:07:17 2010 -0700
@@ -365,12 +365,16 @@
         # determine whether we are doing AI install or slim install
         self.livecd_install = False
         self.auto_install = False
+        self.text_install = False
         if os.access("/.livecd", os.R_OK):
             _dbg_msg('Determined to be doing Live CD install')
             self.livecd_install = True
         elif os.access("/.autoinstall", os.R_OK):
             _dbg_msg('Determined to be doing Automated Install')
             self.auto_install = True
+        elif os.access("/.textinstall", os.R_OK):
+            _dbg_msg("Determined to be doing Text Install")
+            self.text_install = True
 
         if basedir == '':
             prerror('Base directory must be passed')
@@ -380,7 +384,7 @@
             The code can be run on a live system but if we're not
             on a live system we should not support / for BASEDIR.
             '''
-            if ((self.livecd_install) or (self.auto_install)):
+            if self.livecd_install or self.auto_install or self.text_install:
                 err_str = 'Base directory cannot be root ' + \
                     '("/") during install'
                 prerror(err_str)
@@ -392,7 +396,7 @@
         the basedir here since that could be the mountpoint of a
         pool that we're creating the menu.lst file on.
         '''
-        if ((self.livecd_install) or (self.auto_install)):
+        if self.livecd_install or self.auto_install or self.text_install:
             self.prependdir = basedir
         else:
             self.prependdir = ""
@@ -444,7 +448,7 @@
         self.rootpool = rpa[0]
         _dbg_msg('Root pool name discovered: ' + self.rootpool)
 
-        if ((self.livecd_install) or (self.auto_install)):
+        if self.livecd_install or self.auto_install or self.text_install:
             #With the root pool pre-pended to /boot/grub/menu.lst
             self.grubmenu = '/' + self.rootpool + loc_grubmenu
             self.bootmenu_path_sparc = '/' + self.rootpool + '/boot'
@@ -1253,14 +1257,14 @@
         _register_task(inspect.currentframe())
         cmd = 'bootadm update-archive -R ' + self.basedir + ' 2>&1'
         status, cmdout = _cmd_out(cmd)
+        info_msg('bootadm update-archive output: %s' % cmdout)
         if status != 0:
             prerror('Updating boot archive fails. exit status=' +
                     str(status) + ' command=' + cmd)
             prerror('Failure. Returning: ICT_UPDATE_ARCHIVE_FAILED')
             return ICT_UPDATE_ARCHIVE_FAILED
-        for ln in cmdout:
-            info_msg('bootadm update-archive output: ' + ln)
-        return 0
+        else:
+            return 0
 
     def copy_splash_xpm(self):
         '''ICT - copy splash file to grub directory in new root pool
@@ -1620,6 +1624,50 @@
 
         return return_status
 
+    def do_not_configure_network(self):
+        '''ICT - Do not configure any network.  NWAM will be disabled.
+        Net physical default will be enabled.
+        SVCCFG_DTD=basedir + '/usr/share/lib/xml/dtd/service_bundle.dtd.1'
+        SVCCFG_REPOSITORY=basedir + '/etc/svc/repository.db'
+        svccfg -s network/physical:default setprop general/enabled = true
+        svccfg -s network/physical:nwam setprop general/enabled = false
+
+        return 0, otherwise error status
+        '''
+        _register_task(inspect.currentframe())
+
+        return_status = 0
+
+        os.putenv('SVCCFG_DTD', self.basedir +
+                  '/usr/share/lib/xml/dtd/service_bundle.dtd.1')
+        os.putenv('SVCCFG_REPOSITORY', self.basedir + '/etc/svc/repository.db')
+        cmd = '/usr/sbin/svccfg -s network/physical:default setprop ' + \
+              'general/enabled = true 2>&1'
+        status, oa = _cmd_out(cmd)
+        if status != 0:
+            prerror('Command to disable network/physical:default failed. ' + \
+                    'exit status=' + str(status))
+            prerror('Command to disable network/physical:default was: ' + cmd)
+            for ln in oa:
+                prerror(ln)
+            prerror('Failure. Returning: ICT_SVCCFG_FAILURE')
+            return(ICT_SVCCFG_FAILURE)
+
+        cmd = '/usr/sbin/svccfg -s network/physical:nwam setprop ' + \
+              'general/enabled = false 2>&1'
+        status, oa = _cmd_out(cmd)
+        if status != 0:
+            prerror('Command to disable nwam failed. exit status=' + \
+                    str(status))
+            prerror('Command to disable nwam was: ' + cmd)
+            for ln in oa:
+                prerror(ln)
+
+            prerror('Failure. Returning: ICT_SVCCFG_FAILURE')
+            return (ICT_SVCCFG_FAILURE)
+
+        return return_status
+
     def remove_livecd_environment(self):
         '''ICT - Copy saved configuration files to remove vestiges of
         live CD environment
@@ -1629,7 +1677,8 @@
         if not os.path.exists(savedir):
             info_msg('saved configuration files directory is missing')
             return 0 # empty - assume no config files to back up
-        cmd = '(cd %s && find . -type f -print | cpio -pmu %s) && rm -rf %s' \
+        cmd = '(cd %s && find . -type f -print | \
+            /bin/cpio -pmu %s > /dev/null 2>& 1) && rm -rf %s' \
             % (savedir, self.basedir, savedir)
         status = _cmd_status(cmd)
         if status == 0:
@@ -1939,7 +1988,8 @@
         - return None if none is found
         '''
 
-        if ((not self.livecd_install) and (not self.auto_install)):
+        if (not self.livecd_install and not self.auto_install and
+            not self.text_install):
             # Not going to have .image_info file
             return None
 
@@ -1951,7 +2001,7 @@
         #
         grub_title = None
         img_info_fd = None
-        if (self.livecd_install):
+        if (self.livecd_install or self.text_install):
             img_info_file = "/.cdrom/.image_info"
         else:
             img_info_file = "/tmp/.image_info"
@@ -2302,6 +2352,7 @@
         # the basedir directory that are not needed by the installed OS.
         file_cleanup_list = [ "/.livecd",
                               "/.volumeid",
+                              "/.textinstall",
                               "/etc/sysconfig/language",
                               "/.liveusb" ]
         dir_cleanup_list = [ "/a", "/bootcd_microroot" ]
@@ -2326,18 +2377,19 @@
                 prerror('Unexpected error deleting directory.')
                 prerror(traceback.format_exc())
 
-	# Since SUNWgrub delivers the reference grub menu file
-	# (/boot/grub/menu.lst) we'll have to copy the menu.lst
-	# file from the microroot into the installed system.
-	# Since this file is for reference only if the copy
-	# fails we don't want to stop the install for this but
-	# we should log it.
-        try:
-            shutil.copy2("/boot/grub/menu.lst", self.basedir + \
-                "/boot/grub/menu.lst")
-        except OSError, (errno, strerror):
-            prerror('Error copying /boot/grub/menu.lst to ' + self.basedir + \
-                '/boot/grub/menu.lst :' + strerror)
+        # Since SUNWgrub delivers the reference grub menu file
+        # (/boot/grub/menu.lst) we'll have to copy the menu.lst
+        # file from the microroot into the installed system.
+        # Since this file is for reference only if the copy
+        # fails we don't want to stop the install for this but
+        # we should log it.
+        if not self.is_sparc:
+            try:
+                shutil.copy2("/boot/grub/menu.lst", self.basedir +
+                             "/boot/grub/menu.lst")
+            except (OSError,IOError) as err:
+                prerror('Error copying /boot/grub/menu.lst to ' +
+                        self.basedir + '/boot/grub/menu.lst :' + str(err))
 
         # The bootcd_microroot directory should be cleaned up in the
         # Distribution Constructor once they have finished the redesign.
@@ -2518,6 +2570,7 @@
         info_msg('grubmenu: ' + str(self.grubmenu))
         info_msg('is_sparc: ' + str(self.is_sparc))
         info_msg('livecd_install: ' + str(self.livecd_install))
+        info_msg('text_install: ' + str(self.text_install))
         info_msg('kbd_defaults_file: ' + str(self.kbd_defaults_file))
         info_msg('kbd_device: ' + str(self.kbd_device))
         info_msg('kbd_layout_file: ' + str(self.kbd_layout_file))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,101 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# Target Instantiation software library makefile
+#
+
+LIBRARY	= tgt
+
+OBJECTS	= \
+	discover.o \
+	disk.o \
+	geometry.o \
+	instantiate.o \
+	partition.o \
+	slice.o \
+	tgt.o \
+	zpool.o
+
+CPYTHONLIBS = tgt.so
+
+PRIVHDRS = tgt.h
+
+EXPHDRS =
+
+HDRS		= $(EXPHDRS) $(PRIVHDRS)
+
+include ../Makefile.lib
+
+PYVERSION=python2.6
+PYINCLUDE=-I/usr/include/$(PYVERSION) -I../libtd -I../libti
+
+INCLUDE		 = -I. \
+		   -I../libtd \
+		   -I../libti \
+		   $(PYINCLUDE) \
+		   -I$(ROOTINCADMIN)
+
+CPPFLAGS	+= $(INCLUDE) -D$(ARCH)
+CFLAGS		+= $(DEBUG_CFLAGS) -Xa $(CPPFLAGS) -xc99
+LDFLAGS		+=
+SOFLAGS		+= -L$(ROOTADMINLIB) -R$(ROOTADMINLIB:$(ROOT)%=%) \
+		-L$(ROOTUSRLIB) -R$(ROOTUSRLIB:$(ROOT)%=%) -ltd -lti \
+		-Mmapfile-vers
+
+PYMODULES=	tgt_utils.py
+
+PYCMODULES=	$(PYMODULES:%.py=%.pyc)
+ROOTPYMODULES=  $(PYMODULES:%=$(ROOTPYTHONVENDORINSTALL)/%)
+ROOTPYCMODULES= $(PYCMODULES:%=$(ROOTPYTHONVENDORINSTALL)/%)
+
+# Can't include libdiskmgmt.h if it thinks we are 64-bit
+#pics/$(ARCH)/disk.o:=CFLAGS += -D_FILE_OFFSET_BITS=32
+
+static: $(OBJECTS)
+
+dynamic: $(CPYTHONLIB)
+
+all: $(HDRS) dynamic python
+
+install_h:
+
+install:	all .WAIT \
+		$(ROOTPYTHONVENDOR) \
+		$(ROOTPYTHONVENDORINSTALL) \
+		$(ROOTPYTHONVENDORINSTALLLIBS) \
+		$(ROOTPYTHONVENDORINSTALLMODS) \
+		$(ROOTPYTHONVENDORINSTALLCMODS) \
+		$(ROOTPYMODULES) \
+		$(ROOTPYCMODULES)
+
+
+lint:  $(SRCS) $(HDRS)
+	$(LINT.c) $(SRCS)
+
+python:
+	$(PYTHON) -m compileall -l $(@D)
+
+cstyle:	$(SRCS) $(PRIVHDRS) $(PUBHDRS)
+	$(CSTYLE) $(SRCS) $(PRIVHDRS) $(PUBHDRS)
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/discover.c	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,795 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "geometry.h"
+#include "disk.h"
+#include "partition.h"
+#include "slice.h"
+#include "tgt.h"
+#include "td_api.h"
+
+static TgtGeometry	*TgtGeometry_Create(nvlist_t *);
+static TgtDisk		*TgtDisk_Create(nvlist_t *, TgtGeometry *);
+static TgtPartition	*TgtPartition_Create(nvlist_t *, TgtGeometry *);
+static TgtSlice		*TgtSlice_Create(nvlist_t *, TgtGeometry *);
+
+static PyObject		*TgtDisk_enumerate(int);
+#ifndef	sparc
+static PyObject		*TgtPartition_enumerate(TgtDisk *);
+#endif
+static PyObject		*TgtSlice_enumerate(TgtDisk *);
+
+/* Macro to simplify creating a new target object */
+#define	Tgt_NEW(tp)	(tp *)tp##Type.tp_new(&tp##Type, NULL, NULL)
+
+
+/*
+ * Function:    discover_target_data
+ * Description: discover all disks, partitions, and slices.
+ * Parameters:  None
+ * Returns:     list of Disk objects
+ * Scope:       Private
+ */
+PyObject *
+discover_target_data(void)
+{
+	PyObject *result = NULL; /* tuple of TgtDisk */
+	PyObject *list = NULL;
+	PyObject *tmp = NULL;
+
+	int idx, ndisk, num, rc;
+
+	/*
+	 * Allow this function to run in a Python thread without blocking
+	 * the Python interpreter
+	 */
+	Py_BEGIN_ALLOW_THREADS
+	rc = td_discover(TD_OT_DISK, &ndisk);
+	Py_END_ALLOW_THREADS
+
+	/* get number of disks */
+	switch (rc) {
+	case TD_E_SUCCESS:
+		break;
+	case TD_E_NO_DEVICE:
+		/* There are no disks, return empty tuple */
+		result = PyTuple_New(0); /* will set PyErr_NoMemory() on fail */
+		return (result);
+	default:
+		raise_td_errcode();
+		return (NULL);
+	}
+
+
+	list = TgtDisk_enumerate(ndisk);
+	if (list == NULL && PyErr_Occurred() != NULL)
+		return (NULL);
+
+
+	/*
+	 * From this point on we must Py_DECREF(result) and set result
+	 * back to NULL on error.
+	 */
+	result = PyList_AsTuple(list);
+	Py_DECREF(list);
+
+	/* use a precise count for getting partitions/slices */
+	ndisk = PyTuple_GET_SIZE(result);
+
+	/* get partitions */
+#ifndef sparc /* Makefile sets this, do not look for partitions on SPARC */
+	for (idx = 0; idx < ndisk; idx++) {
+		PyObject *list = NULL;
+		TgtDisk *disk = (TgtDisk *)PyTuple_GET_ITEM(result, idx);
+		assert(TgtDisk_CheckExact(disk));
+
+		list = TgtPartition_enumerate(disk);
+		if (list == NULL) {
+			Py_DECREF(result);
+			return (NULL);
+		}
+
+		/* partition order is about sorting and makes no sense in C */
+
+		/* create tuple and assign to disk->children */
+		tmp = disk->children;
+		disk->children = PyList_AsTuple(list);
+		Py_XDECREF(tmp);
+		Py_DECREF(list);
+	}
+#endif	/* sparc not defined */
+
+	/*
+	 * Look up slices. If children is 0 go for it.
+	 * If children is not 0 (there are partitions), we look up slices and
+	 * assume they belong to the active partition. If there is just 1
+	 * Solaris/Solaris2 partition the slices clearly belong to that
+	 * Partition. Only 1 solaris allowed per disk, but if more are found
+	 * we can't assign slices to any of them.
+	 */
+	for (idx = 0; idx < ndisk; idx++) {
+		int nchild = 0;
+		PyObject **tuplep = NULL;
+		nvlist_t **iterl = NULL;
+		nvlist_t **attrl = NULL;
+		TgtGeometry *geo = NULL;
+		TgtDisk *disk = (TgtDisk *)PyTuple_GET_ITEM(result, idx);
+		assert(TgtDisk_CheckExact(disk));
+		geo = (TgtGeometry *)disk->geometry;
+
+		/* Figure out where slices go / if to look for them */
+		nchild = PyTuple_GET_SIZE(disk->children);
+		if (nchild == 0) {
+			/* no partitions look for slices */
+			tuplep = &(disk->children);
+		} else {
+			/*
+			 * Have partitions, if number of Solaris/Solaris2 > 1
+			 * and none are active we don't look for slices.
+			 * If number of Solaris/Solaris2 equals 1 or one of
+			 * the Solaris/Solaris2 is the active partition then
+			 * search for slices.
+			 */
+			int pidx;
+			int nsolaris = 0;
+			TgtPartition *solpart = NULL;
+
+			for (pidx = 0; pidx < nchild; pidx++) {
+				TgtPartition *part;
+				part = (TgtPartition *)PyTuple_GET_ITEM(
+				    disk->children, pidx);
+				switch (part->type) {
+				case 0x82: /* fallthrough */
+				case 0xBF:
+					solpart = part;
+					nsolaris++;
+					/* solaris partition, check active */
+					if (part->active == 1) {
+						break;
+					}
+				default:
+					continue;
+				}
+			}
+			/* Setting tuplep will trigger a search */
+			if (solpart && solpart->active == 1 || nsolaris == 1) {
+				tuplep = &(solpart->children);
+			}
+		}
+
+		if (tuplep == NULL) {
+			/*
+			 * Don't look for slices on this disk
+			 * This happens when the partition that would be
+			 * associated with the slices can't be determined.
+			 */
+			assert(nchild > 0);
+			continue;
+		}
+
+		/* it should be a valid tuple we are pointing to with size 0 */
+		assert(*tuplep != NULL);
+		assert(PyTuple_Check(*tuplep));
+		assert(PyTuple_GET_SIZE(*tuplep) == 0);
+
+
+		list = TgtSlice_enumerate(disk);
+		if (list == NULL) {
+			Py_DECREF(result);
+			return (NULL);
+		}
+
+		tmp = *tuplep;
+		*tuplep = PyList_AsTuple(list);
+		Py_XDECREF(tmp);
+		Py_DECREF(list);
+	}
+
+	return (result);
+}
+PyDoc_STRVAR(discover_target_data_doc,
+"discover_target_data() -> tuple of tgt.Disk objects");
+
+/*
+ * Function:	TgtDisk_enumerate
+ * Description:	enumerate target disks available.
+ * Parameters:
+ * 	ndisk	number of disks (although some may not be valid).
+ * Returns:	PyObject pointer that is a list of disks. Or NULL
+ *		in case of error (exception set for Python).
+ * Scope:	Private
+ *
+ * N.B.: libtd.so does not distinguish between disk and geometry,
+ *       we do. So this reads up both at the same time.
+ */
+static PyObject*
+TgtDisk_enumerate(int ndisk)
+{
+	PyObject *result = NULL; /* our list */
+	int idx, rc;
+
+	if ((result = PyList_New(0)) == NULL)
+		return (PyErr_NoMemory());
+
+	for (idx = 0; idx < ndisk; idx++) {
+		TgtGeometry *geo = NULL;
+		TgtDisk *disk = NULL;
+		nvlist_t *attr = NULL;
+
+		rc = td_get_next(TD_OT_DISK); /* doesn't go to disk */
+		if (rc != TD_E_SUCCESS) {
+			continue; /* bad disk */
+		}
+
+		Py_BEGIN_ALLOW_THREADS
+		attr = td_attributes_get(TD_OT_DISK);
+		Py_END_ALLOW_THREADS
+		if (attr == NULL) {
+			continue; /* bad disk */
+		}
+
+		geo = TgtGeometry_Create(attr);
+		/*
+		 * disk could have had unacceptable geometry, in which case
+		 * NULL is returned and no error is set.
+		 */
+		if (geo != NULL) {
+			disk = TgtDisk_Create(attr, geo);
+		}
+		nvlist_free(attr); /* done in any case */
+
+		if (geo == NULL) {
+			if (PyErr_Occurred() == NULL)
+				continue;
+			goto TgtDisk_enumerate_CLEANUP;
+		}
+		Py_DECREF(geo); /* disk holds ref but we are done with it */
+
+		if (PyList_Append(result, (PyObject *)disk)) {
+			PyErr_NoMemory();
+			goto TgtDisk_enumerate_CLEANUP;
+		}
+	}
+
+	return (result);
+
+TgtDisk_enumerate_CLEANUP:
+	Py_XDECREF(result);
+	return (NULL);
+}
+
+#ifndef	sparc /* only build this if not sparc */
+/*
+ * Function:	TgtPartition_enumerate
+ * Description:	enumerate target partitions for a single disk.
+ * Parameters:
+ * 	ndisk	number of disks (although some may not be valid).
+ * Returns:	PyObject pointer that is a list of Partitions. Or
+ * 		NULL in case of error (exception set for Python).
+ * Scope:	Private
+ */
+static PyObject*
+TgtPartition_enumerate(TgtDisk *disk)
+{
+	PyObject *result = NULL; /* list of partitions */
+	TgtGeometry *geo = NULL;
+	nvlist_t **iterl = NULL;
+	nvlist_t **attrl = NULL;
+	int idx, num;
+
+	assert(disk != NULL);
+	geo = (TgtGeometry *)disk->geometry;
+
+
+	if ((result = PyList_New(0)) == NULL)
+		return (PyErr_NoMemory());
+
+	/* this returns an nvlist_t which contains nvlist_t */
+	Py_BEGIN_ALLOW_THREADS
+	attrl = td_discover_partition_by_disk(disk->name, &num);
+	Py_END_ALLOW_THREADS
+
+	for (idx = 0, iterl = attrl; idx < num; idx++, iterl++) {
+		TgtPartition *part = TgtPartition_Create(*iterl, geo);
+		if (part == NULL) {
+			if (PyErr_Occurred() == NULL)
+				continue;
+			goto TgtPartition_enumerate_CLEANUP;
+		}
+		if (PyList_Append(result, (PyObject *)part)) {
+			Py_DECREF(part);
+			PyErr_NoMemory();
+			goto TgtPartition_enumerate_CLEANUP;
+		}
+	}
+	td_attribute_list_free(attrl);
+	return (result);
+
+TgtPartition_enumerate_CLEANUP:
+	/* You need to have set error before jumping here */
+	td_attribute_list_free(attrl);
+	Py_XDECREF(result);
+
+	return (NULL);
+}
+#endif	/* sparc : only build this if not sparc */
+
+/*
+ * Function:	TgtSlice_enumerate
+ * Description:	enumerate target slices for a single disk.
+ * Parameters:
+ * 	disk	target disk to enumerate.
+ * Returns:	PyObject pointer that is a list of Slices. Or
+ * 		NULL in case of error (exception set for Python).
+ * Scope:	Private
+ */
+static PyObject*
+TgtSlice_enumerate(TgtDisk *disk)
+{
+	PyObject *result = NULL; /* list of slices */
+	TgtGeometry *geo = NULL;
+	nvlist_t **iterl = NULL;
+	nvlist_t **attrl = NULL;
+	int idx, num;
+
+	assert(disk != NULL);
+	geo = (TgtGeometry *)disk->geometry;
+
+	if ((result = PyList_New(0)) == NULL)
+		return (PyErr_NoMemory());
+
+	Py_BEGIN_ALLOW_THREADS
+	attrl = td_discover_slice_by_disk(disk->name, &num);
+	Py_END_ALLOW_THREADS
+	if (num <= 0 || num > NDKMAP) {
+		td_attribute_list_free(attrl);
+		return (result); /* empty list */
+	}
+
+	for (idx = 0, iterl = attrl; idx < num; idx++, iterl++) {
+		TgtSlice *slice = TgtSlice_Create(*iterl, geo);
+		if (slice == NULL) {
+			if (PyErr_Occurred() == NULL)
+				continue;
+			goto TgtSlice_enumerate_CLEANUP;
+		}
+		if (PyList_Append(result, (PyObject *)slice)) {
+			Py_DECREF(slice);
+			PyErr_NoMemory();
+			goto TgtSlice_enumerate_CLEANUP;
+		}
+	}
+	td_attribute_list_free(attrl);
+
+	return (result);
+
+TgtSlice_enumerate_CLEANUP:
+	/* You need to have set error before jumping here */
+	td_attribute_list_free(attrl);
+	Py_XDECREF(result);
+
+	return (NULL);
+}
+
+/*
+ * Function:	TgtGeometry_Create
+ * Description:	fill in a tgt.Geometry object correctly.
+ * Parameters:	None
+ * Returns:	TgtGeometry that is the tgt.Geometry object.
+ * Scope:	Private
+ *
+ * N.B.: If we get a disk with unacceptable values we return NULL.
+ *       So you must check for an error condition using PyErr_Occurred()
+ *       to see if that is NULL.
+ */
+static TgtGeometry *
+TgtGeometry_Create(nvlist_t *disk_list)
+{
+	TgtGeometry *geometry = NULL;
+	char *str = NULL;
+	uint32_t bsz, val, nsect, nhead, cylsz;
+	uint64_t nblock;
+
+	assert(disk_list != NULL);
+
+	/*
+	 * TgtGeometry_Create(), is caled first so it needs to do the sanity
+	 * checking of the disk. If we are skipping this one there is no
+	 * point in creating a geometry.
+	 *
+	 * Most data it looks up is ignored but will be used in
+	 * TgtDisk_Create() should this pass.
+	 */
+	if (nvlist_lookup_uint32(disk_list, TD_DISK_ATTR_MTYPE, &val) == 0) {
+		if (val != TD_MT_FIXED)
+			goto TgtGeometry_Create_SKIP_DISK;
+	} else {
+		goto TgtGeometry_Create_SKIP_DISK;
+	}
+
+	bsz = nblock = 0;
+	(void) nvlist_lookup_uint32(disk_list, TD_DISK_ATTR_BLOCKSIZE, &bsz);
+	(void) nvlist_lookup_uint64(disk_list, TD_DISK_ATTR_SIZE, &nblock);
+	if (bsz == 0 || nblock == 0) {
+		/* bad geometry -- may consider a debug print here? */
+		goto TgtGeometry_Create_SKIP_DISK;
+	}
+
+	/* this is odd as we don't even use this stuff */
+	if ((nvlist_lookup_uint32(disk_list, TD_DISK_ATTR_NHEADS, &nsect)
+	    != 0) || (nvlist_lookup_uint32(disk_list, TD_DISK_ATTR_NSECTORS,
+	    &nhead) != 0)) {
+		/* fake the cylsz to be identical to block size */
+		cylsz = bsz;
+	} else {
+		cylsz = nsect * nhead;
+	}
+
+	if (nvlist_lookup_string(disk_list, TD_DISK_ATTR_NAME, &str) != 0) {
+		/* have to be able to reference the disk */
+		goto TgtGeometry_Create_SKIP_DISK;
+	}
+
+	geometry = Tgt_NEW(TgtGeometry);
+	if (geometry == NULL) {
+		return ((TgtGeometry *)PyErr_NoMemory());
+	}
+
+	geometry->blocksz = bsz;
+	geometry->cylsz = cylsz;
+
+	return (geometry);
+
+TgtGeometry_Create_SKIP_DISK:
+	/* This label assumes you have not created any objects */
+	PyErr_Clear(); /* make sure no error set */
+	return (NULL);
+}
+
+/*
+ * Function:	TgtDisk_Create
+ * Description:	fill in a tgt.Disk object correctly.
+ * Parameters:	None
+ * Returns:	TgtDisk that is the tgt.Disk object.
+ * Scope:	Private
+ *
+ * N.B.: If we get a disk with unacceptable values (like bad geometry) we return
+ *       NULL. So you must check for an error condition using PyErr_Occurred()
+ *       to see if that is NULL.
+ */
+static TgtDisk *
+TgtDisk_Create(nvlist_t *disk_list, TgtGeometry *geo)
+{
+	TgtDisk *disk = NULL;
+	PyObject *constantref = NULL;
+	PyObject *tmp = NULL;
+	char *str = NULL;
+	uint32_t val;
+	uint64_t nblock;
+
+	assert(disk_list != NULL);
+
+	/*
+	 * TgtGeometry_Create() already verified the disk.
+	 */
+	disk = Tgt_NEW(TgtDisk);
+	if (disk == NULL) {
+		PyErr_NoMemory();
+		goto TgtDisk_Create_CLEANUP;
+	}
+
+	/*
+	 * can cheat a bit here b/c we know nobody has seen this Object yet
+	 * and b/c we know if goemetry is set to TgtGeometryDefault.
+	 */
+	assert(disk->geometry == TgtGeometryDefault);
+	Py_DECREF(disk->geometry);
+	Py_INCREF(geo);
+	disk->geometry = (PyObject *)geo;
+
+	(void) nvlist_lookup_uint64(disk_list, TD_DISK_ATTR_SIZE, &nblock);
+	assert(nblock != 0);
+	disk->blocks = nblock;
+	(void) nvlist_lookup_string(disk_list, TD_DISK_ATTR_NAME, &str);
+	assert(str != NULL);
+	disk->name = strdup(str); /* this still has name */
+	if (disk->name == NULL) {
+		PyErr_NoMemory();
+		goto TgtDisk_Create_CLEANUP;
+	}
+
+	/* controller already set to default */
+	constantref = DiskConst.unknown; /* default */
+	if ((nvlist_lookup_string(disk_list, TD_DISK_ATTR_CTYPE, &str) == 0) &&
+	    (str != NULL)) {
+		while (1) {
+#define			CONSTANT(v, cname, pyname, value) \
+			if (strcmp(str, value) == 0) { \
+				constantref = DiskConst.cname; \
+				break; \
+			}
+			CONTROLLER_CONSTANTS
+#undef			CONSTANT
+			break; /* leave it as "unknown" */
+		}
+	}
+	tmp = disk->controller;
+	Py_INCREF(constantref);
+	disk->controller = constantref;
+	Py_XDECREF(tmp);
+
+	disk->vtoc = disk->gpt = disk->fdisk = 0;
+	if (nvlist_lookup_uint32(disk_list, TD_DISK_ATTR_LABEL, &val) == 0) {
+		/*
+		 * we just trust that it is something we understand.
+		 * That way instantiation can use it. But if it isn't in
+		 * LABEL_CONSTANTS it will print as "unknown".
+		 */
+		disk->vtoc = (val & TD_DISK_LABEL_VTOC) ? 1 : 0;
+		disk->gpt = (val & TD_DISK_LABEL_GPT) ? 1 : 0;
+		disk->fdisk = (val & TD_DISK_LABEL_FDISK) ? 1 : 0;
+	}
+
+	disk->removable = disk->boot = 0;
+	if (nvlist_lookup_boolean(disk_list, TD_DISK_ATTR_REMOVABLE) == 0) {
+		disk->removable = 1;
+	}
+	if (nvlist_lookup_boolean(disk_list, TD_DISK_ATTR_CURRBOOT) == 0) {
+		disk->boot = 1;
+	}
+
+	disk->serialno = NULL; /* not implemented in libtd.so */
+	disk->vendor = NULL;
+	if ((nvlist_lookup_string(disk_list, TD_DISK_ATTR_VENDOR, &str) == 0) &&
+		(str != NULL)) {
+		/* if it is the string "unknown" then leave NULL */
+		if (strcmp(str, "unknown") != 0) {
+			disk->vendor = strdup(str); /* its OK if it failed */
+		}
+	}
+
+	/* Verify children is null tuple */
+	assert(disk->children != NULL);
+	assert(PyTuple_Check(disk->children));
+	assert(PyTuple_GET_SIZE(disk->children) == 0);
+
+	return (disk);
+
+TgtDisk_Create_CLEANUP:
+	Py_XDECREF(disk);
+	return (NULL);
+
+TgtDisk_Create_SKIP_DISK:
+	/* This label assumes you have not created any objects */
+	PyErr_Clear(); /* make sure no error set */
+	return (NULL);
+}
+
+
+/*
+ * Function:	TgtPartition_Create
+ * Description:	fill in a tgt.Partition object correctly.
+ * Parameters:	None
+ * Returns:	TgtPartition that is the tgt.Partition object.
+ * Scope:	Private
+ *
+ * N.B.: If we get a partition with unacceptable values we return
+ *       NULL. So you must check for an error condition using PyErr_Occurred()
+ *       to see if that is NULL.
+ */
+static TgtPartition *
+TgtPartition_Create(nvlist_t *part_list, TgtGeometry *geo)
+{
+	TgtPartition *part = NULL;
+	PyObject *list = NULL;
+	PyObject *tmp = NULL;
+	char *str = NULL;
+	char *ptr = NULL;
+	nvlist_t **attr_list_list = NULL;
+	nvlist_t **attr_list_iter = NULL;
+	int idx, num;
+	uint32_t val;
+
+	if (nvlist_lookup_string(part_list, TD_PART_ATTR_NAME, &str) != 0) {
+		goto TgtPartition_Create_SKIP_PARTITON;
+	}
+
+	/* If the partition name is not ending with pX ignore this partition */
+	ptr = str + strlen(str) - 2;
+	if (*ptr == 'p') {
+		ptr++;
+	} else {
+		ptr = str + strlen(str) - 3;
+		if (*ptr == 'p') {
+			ptr++;
+		} else {
+			goto TgtPartition_Create_SKIP_PARTITON;
+		}
+	}
+
+	part = Tgt_NEW(TgtPartition);
+	if (part == NULL) {
+		return (NULL); /* sets mem error */
+	}
+
+	assert(part->geometry == TgtGeometryDefault);
+	Py_DECREF(part->geometry);
+	Py_INCREF(geo);
+	part->geometry = (PyObject *)geo;
+
+
+	/* The partition is of the form cXtXdXpX */
+	errno = 0;
+	part->id = (uint8_t)strtol(ptr, (char **)NULL, 10);
+	if (errno != 0) {
+		/* just skip */
+		goto TgtPartition_Create_CLEANUP;
+	}
+
+	part->active = 0;
+	if (nvlist_lookup_uint32(part_list, TD_PART_ATTR_BOOTID, &val) == 0) {
+		if (val & ACTIVE)
+			part->active = 1;
+	}
+
+	if (nvlist_lookup_uint32(part_list, TD_PART_ATTR_TYPE, &val) == 0) {
+		part->type = (uint16_t)val; /* type/content 0-255 */
+	}
+
+	if (part->type == 0x82) {
+		/*
+		 * Original Solaris and Linux Swap share 0x82.
+		 * Disambiguate now. On failure assume Solaris.
+		 */
+		if (nvlist_lookup_uint32(part_list, TD_PART_ATTR_CONTENT, &val)
+		    == 0) {
+			if (val != 0) {
+				part->type = 0x182;
+			}
+		}
+	}
+
+	if (nvlist_lookup_uint32(part_list, TD_PART_ATTR_START, &val) == 0) {
+		part->offset = val; /* not 64-bit? */
+	}
+
+	if (nvlist_lookup_uint32(part_list, TD_PART_ATTR_SIZE, &val) == 0) {
+		part->blocks = val; /* not 64-bit? */
+	}
+
+	/* Verify children is null tuple */
+	assert(part->children != NULL);
+	assert(PyTuple_Check(part->children));
+	assert(PyTuple_GET_SIZE(part->children) == 0);
+
+	return (part);
+
+TgtPartition_Create_CLEANUP:
+	Py_XDECREF(part);
+	return (NULL);
+
+TgtPartition_Create_SKIP_PARTITON:
+	/* This label assumes you have not created any objects */
+	PyErr_Clear(); /* make sure no error set */
+	return (NULL);
+}
+
+
+/*
+ * Function:	TgtSlice_Create
+ * Description:	fill in a tgt.Slice object correctly.
+ * Parameters:	None
+ * Returns:	TgtSlice that is the tgt.Slice object.
+ * Scope:	Private
+ */
+TgtSlice *
+TgtSlice_Create(nvlist_t *slice_list, TgtGeometry *geo)
+{
+	TgtSlice *slice = NULL;
+	PyObject *tmpo = NULL;
+	char *str = NULL;
+	uint32_t v32;
+	uint64_t v64;
+
+
+	if (nvlist_lookup_string(slice_list, TD_SLICE_ATTR_NAME, &str) != 0) {
+		/*
+		 * presence needed for valid slice, but we don't need this to
+		 * get valid id like partition.
+		 */
+		goto TgtSlice_Create_SKIP_SLICE;
+	}
+
+	slice = Tgt_NEW(TgtSlice);
+	if (slice == NULL) {
+		return (NULL); /* sets mem error */
+	}
+
+	assert(slice->geometry == TgtGeometryDefault);
+	Py_DECREF(slice->geometry);
+	Py_INCREF(geo);
+	slice->geometry = (PyObject *)geo;
+
+	if (nvlist_lookup_uint32(slice_list, TD_SLICE_ATTR_INDEX, &v32) == 0) {
+		slice->number = v32;
+	}
+
+	if (nvlist_lookup_uint64(slice_list, TD_SLICE_ATTR_START, &v64) == 0) {
+		slice->offset = v64;
+	}
+
+	if (nvlist_lookup_uint64(slice_list, TD_SLICE_ATTR_SIZE, &v64) == 0) {
+		slice->blocks = v64;
+	}
+
+	if (nvlist_lookup_uint32(slice_list, TD_SLICE_ATTR_FLAG, &v32) == 0) {
+		if ((v32 & V_UNMNT) != 0) { /* unmountable flag set */
+			/* so probably slice 2, "backup" */
+			slice->unmountable = 1;
+		}
+		if ((v32 & V_RONLY) != 0) { /* read only flag set */
+			slice->readonly = 1;
+		}
+	}
+
+	if (nvlist_lookup_uint32(slice_list, TD_SLICE_ATTR_TAG, &v32) == 0) {
+		slice->tag = (uint8_t)v32;
+	}
+
+	if (nvlist_lookup_string(slice_list, TD_SLICE_ATTR_USEDBY, &str) == 0) {
+		while (1) {
+#define			CONSTANT(v, cname, pyname, value) \
+			if (strcmp(str, value) == 0) { \
+				slice->type = v; \
+				break; \
+			}
+			SLICE_USED_BY_CONSTANTS
+#undef			CONSTANT
+			slice->type = (uint8_t)-1;
+			break;
+		}
+	}
+
+	slice->user = NULL;
+	if (nvlist_lookup_string(slice_list, TD_SLICE_ATTR_INUSE, &str) == 0) {
+		slice->user = strdup(str); /* keep a copy */
+	}
+
+	slice->last_mount = NULL;
+	if (nvlist_lookup_string(slice_list, TD_SLICE_ATTR_LASTMNT,
+	    &str) == 0) {
+		if (strcmp(str, "") != 0) {
+			slice->last_mount = strdup(str); /* keep a copy */
+		}
+	}
+
+	return (slice);
+
+TgtSlice_Create_SKIP_SLICE:
+	/* This label assumes you have not created any objects */
+	PyErr_Clear(); /* make sure no error set */
+	return (NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/disk.c	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,676 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "geometry.h"
+#include "disk.h"
+#include "tgt.h"
+#include "boolobject.h"
+#include "td_api.h"
+
+
+disk_const DiskConst;
+
+PyTypeObject TgtDiskType; /* forward declaration */
+
+/*
+ * Function:	init_disk
+ * Description:	fill in the class data for tgt.Disk.
+ *              This is stored in DiskConst and then we make it available
+ *              as data to the class.
+ * Parameters:
+ *     unknown: the shared string "unknown".
+ * Returns:	None
+ * Scope:	Private
+ *
+ * NOTE: You must not call this until after you have called
+ *       PyType_Ready(&TgtDiskType), as this adds to the Type's dictionary.
+ */
+void
+init_disk(PyObject *unknown)
+{
+#define	CONSTANT(v, cname, pyname, value) \
+	DiskConst.cname = PyString_FromString(value);
+	CONTROLLER_CONSTANTS
+#undef	CONSTANT
+	DiskConst.unknown = unknown; /* add the shared constant. */
+
+	/*
+	 * Keep in mind dictionaries don't steal a reference to key or value.
+	 * Which is perfect, we have a pointer to them in SliceConst but now
+	 * when the type object is cleaned up their ref count will go to 0
+	 * and they will disappear.
+	 */
+#define	CONSTANT(v, cname, pyname, value) \
+	PyDict_SetItemString(TgtDiskType.tp_dict, pyname, DiskConst.cname);
+	CONTROLLER_CONSTANTS
+#undef	CONSTANT
+	PyDict_SetItemString(TgtDiskType.tp_dict, "UNKNOWN", unknown);
+}
+
+/*
+ * Function:    TgtDisk_Init
+ * Description: Initialize a tgt.Disk object.
+ * Parameters:
+ *     self:    tgt.Disk object to fill in
+ *     args:    the arguments given to Python to try to init object
+ *     kwds:    similar to args.
+ * Returns:     None
+ * Scope:       Private
+ *
+ * NOTE: when tgt.discover_target_data() is called this is not used.
+ *       This is for creating a layout without using libtd.so.
+ *       Useful for testing and possibly for target instantiation?
+ */
+static int
+TgtDisk_Init(TgtDisk *self, PyObject *args, PyObject *kwds)
+{
+	int rc;
+	char *name = NULL;
+	char *vendor = NULL;
+	char *serialno = NULL;
+	char *controller = NULL;
+	PyObject *tmp = NULL;
+	PyObject *geometry = NULL;
+	PyObject *blocks = NULL; /* Python2.4 missing uint64_t fmt spec */
+	PyObject *vtoc = NULL;
+	PyObject *gpt = NULL;
+	PyObject *fdisk = NULL;
+	PyObject *boot = NULL;
+	PyObject *removable = NULL;
+	PyObject *constantref = NULL;
+	PyObject *use_whole = NULL;
+
+	/* Remember to keep TgtDiskTypeDoc current with this list */
+	static char *kwlist[] = {
+		"geometry", "name", "blocks", "controller", "vtoc", "gpt",
+		"fdisk", "boot", "removable", "vendor", "serialno", "use_whole",
+		NULL
+	};
+
+	/* set default vaules for unrequired args */
+	boot = removable = Py_False;
+	self->vtoc = self->gpt = self->fdisk = 0; /* not set during init */
+
+	rc = PyArg_ParseTupleAndKeywords(args, kwds, "O!sO|sO!O!O!O!O!zzO!",
+	    kwlist, &TgtGeometryType, &geometry, &name, &blocks,
+	    &controller, &PyBool_Type, &vtoc, &PyBool_Type, &gpt,
+	    &PyBool_Type, &fdisk, &PyBool_Type, &boot, &PyBool_Type,
+	    &removable, &vendor, &serialno, &PyBool_Type, &use_whole);
+
+	if (!rc)
+		return (-1);
+
+	/*
+	 * Have to take care that if we return -1 we have correct ref counts.
+	 * On failure, self will be decrefed and  TgtDisk_Deallocate() will
+	 * (probably, unless ref counts off) be called.
+	 */
+	tmp = self->geometry;
+	Py_INCREF(geometry);
+	self->geometry = geometry;
+	Py_XDECREF(tmp);
+
+	/* Python 2.4 has no scan code for a potentially 64-bit value */
+	if (PyLong_Check(blocks)) {
+		self->blocks = PyLong_AsUnsignedLongLong(blocks);
+	} else {
+		if (PyInt_Check(blocks)) {
+			self->blocks = (uint64_t)PyInt_AsLong(blocks);
+		} else {
+			PyErr_SetString(PyExc_TypeError,
+				"tgt.Disk() \"blocks\" an integer is required");
+			return (-1);
+		}
+	}
+
+	/*
+	 * The controller must be a string we recognize, but not necessarily
+	 * the tgt.Disk class constant.
+	 */
+	constantref = DiskConst.unknown; /* default if given NULL/None */
+	while (1) {
+		if (controller == NULL)
+			break;
+
+#define		CONSTANT(v, cname, pyname, value) \
+		if (strcmp(controller, value) == 0) { \
+			constantref = DiskConst.cname; \
+			break; \
+		}
+		CONTROLLER_CONSTANTS
+#undef		CONSTANT
+		if (strcmp(controller,
+		    PyString_AsString(DiskConst.unknown)) == 0) {
+			constantref = DiskConst.unknown;
+			break;
+		}
+
+		/* any unknown value is not acceptable */
+		PyErr_SetString(PyExc_ValueError,
+		    "tgt.Disk() \"controller\" not a CONTROLLER_CONSTANT");
+		return (-1);
+	}
+	tmp = self->controller;
+	Py_INCREF(constantref);
+	self->controller = constantref;
+	Py_XDECREF(tmp);
+
+
+	self->name = strdup(name); /* can't be NULL */
+	if (self->name == NULL) {
+		PyErr_NoMemory();
+		return (-1);
+	}
+	self->vendor = self->serialno = NULL;
+	if (vendor) {
+		self->vendor = strdup(vendor);
+		if (self->vendor == NULL) {
+			PyErr_NoMemory();
+			return (-1);
+		}
+	}
+	if (serialno) {
+		self->serialno = strdup(serialno);
+		if (self->serialno == NULL) {
+			PyErr_NoMemory();
+			return (-1);
+		}
+	}
+
+#define	SET_BOOL(nm) self->nm = (nm == Py_True) ? 1 : 0
+	SET_BOOL(vtoc);
+	SET_BOOL(gpt);
+	SET_BOOL(fdisk);
+	SET_BOOL(boot);
+	SET_BOOL(removable);
+	SET_BOOL(use_whole);
+#undef	SET_BOOL
+
+	return (0);
+}
+
+/*
+ * Function:    TgtDisk_New
+ * Description: allocate and assign sensible initial values to a tgt.Disk.
+ * Parameters:
+ *     type:    type object, do *NOT* assume it is TgtDiskType!
+ *     args:    ignored, exists to match function prototype.
+ *     kwds:    ignored, exists to match function prototype.
+ * Returns:     None
+ * Scope:       Private
+ */
+static PyObject *
+TgtDisk_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+	TgtDisk *self = NULL;
+
+	self = (TgtDisk *)type->tp_alloc(type, 0);
+	if (self == NULL)
+		return (NULL); /* sets memory error */
+
+	/* The only thing that can fail is PyTyple_New so do that first */
+	if ((self->children = PyTuple_New(0)) == NULL) {
+		return (NULL);
+	}
+
+	/* Set everything else to "sensible defaults" */
+	self->geometry = TgtGeometryDefault;
+	Py_INCREF(TgtGeometryDefault);
+	self->controller = DiskConst.unknown;
+	Py_INCREF(self->controller);
+
+	self->name = self->vendor = self->serialno = NULL;
+	self->blocks = 0;
+	self->vtoc = self->gpt = self->fdisk = 0;
+	self->boot = self->removable = self->use_whole = 0;
+
+	return ((PyObject *)self);
+}
+
+
+/*
+ * Function:	TgtDisk_Deallocate
+ * Description:	Free up a TgtDisk
+ * Parameters:
+ * 	self:	TgtDisk to de-allocate
+ * Returns:	Nothing
+ * Scope:	Private
+ */
+static void
+TgtDisk_Deallocate(TgtDisk *self)
+{
+	Py_XDECREF(self->geometry);
+	Py_XDECREF(self->children);
+	Py_XDECREF(self->controller);
+#define	FREE_STR(cname)			\
+	if (self->cname != NULL) {	\
+		free(self->cname);	\
+		self->cname = NULL;	\
+	}
+
+	FREE_STR(name)
+	FREE_STR(vendor)
+	FREE_STR(serialno)
+#undef	FREE_STR
+
+	self->ob_type->tp_free((PyObject*)self);
+}
+
+static int
+TgtDisk_copy_common(TgtDisk *orig, TgtDisk *copy)
+{
+	PyObject *tmp = NULL;
+
+	/* Geometry is always shared */
+	tmp = copy->geometry;
+	Py_INCREF(orig->geometry);
+	copy->geometry = orig->geometry;
+	Py_XDECREF(tmp);
+
+	tmp = copy->controller;
+	Py_INCREF(orig->controller);
+	copy->controller = orig->controller;
+	Py_XDECREF(tmp);
+
+
+#define	STRCOPY(member) \
+	if (orig->member != NULL) { \
+		copy->member = strdup(orig->member); \
+		if (copy->member == NULL) { \
+			PyErr_NoMemory(); \
+			return (-1); \
+		} \
+	}
+
+	STRCOPY(name);
+	STRCOPY(vendor);
+	STRCOPY(serialno);
+#undef	STRCOPY
+
+#define	SET_MEMBER(member) copy->member = orig->member
+	SET_MEMBER(blocks);
+	SET_MEMBER(vtoc);
+	SET_MEMBER(gpt);
+	SET_MEMBER(fdisk);
+	SET_MEMBER(boot);
+	SET_MEMBER(removable);
+	SET_MEMBER(use_whole);
+#undef	SET_MEMBER
+
+	return (0);
+}
+static PyObject*
+TgtDisk_copy(TgtDisk* self, PyObject* args)
+{
+	TgtDisk *copy = NULL;
+	PyObject *tmp = NULL;
+
+	if (!PyArg_ParseTuple(args, ":__copy__"))
+		return (NULL);
+
+	copy = (TgtDisk *)TgtDiskType.tp_new(&TgtDiskType, NULL, NULL);
+
+	if (copy == NULL)
+		return (PyErr_NoMemory());
+
+	if (TgtDisk_copy_common(self, copy) != 0) {
+		Py_DECREF(copy);
+		return (NULL);
+	}
+
+	/* for copy we just need references */
+	tmp = copy->children;
+	Py_INCREF(self->children);
+	copy->children = self->children;
+	Py_XDECREF(tmp);
+
+	return ((PyObject *)copy);
+}
+static PyObject*
+TgtDisk_deepcopy(TgtDisk* self, PyObject* args)
+{
+	int rc, idx;
+	TgtDisk *copy = NULL;
+	PyObject *memo = NULL;
+	PyObject *tmp = NULL;
+	PyObject *children = NULL;
+
+	if (!PyArg_ParseTuple(args, "O!:__deepcopy__", &PyDict_Type, &memo))
+		return (NULL);
+
+
+	/* check and make sure we haven't copied this already. */
+	rc = PyDict_Contains(memo, (PyObject *)self);
+	switch (rc) {
+	case -1: /* error */
+		return (NULL); /* err should be set */
+	case 1:
+		tmp = PyDict_GetItem(memo, (PyObject *)self);
+		Py_INCREF(tmp);
+		return (tmp); /* don't copy again */
+	}
+	assert(rc == 0);
+
+
+	copy = (TgtDisk *)TgtDiskType.tp_new(&TgtDiskType, NULL, NULL);
+	if (copy == NULL)
+		return (PyErr_NoMemory());
+
+	if (TgtDisk_copy_common(self, copy) != 0) {
+		Py_DECREF(copy);
+		return (NULL);
+	}
+
+	/* need a new children tuple with new children elements of tuple */
+	rc = PyTuple_Size(self->children);
+
+	children = PyTuple_New(rc);
+	for (idx = 0; idx < rc; idx++) {
+		PyObject *oldc, *newc;
+		oldc = PyTuple_GetItem(self->children, idx);
+
+		assert((TgtPartition_Check(oldc) || TgtSlice_Check(oldc)));
+		/*
+		 * can't assume its tgt.Partition or tgt.Slice, could be a
+		 * subclass.
+		 */
+		newc = PyObject_CallMethod(oldc, "__deepcopy__", "O", memo);
+		if (newc == NULL || PyTuple_SetItem(children, idx, newc) != 0) {
+			Py_XDECREF(newc);
+			Py_DECREF(children);
+			Py_DECREF(copy);
+			return (NULL);
+		}
+	}
+
+	tmp = copy->children;
+	copy->children = children;
+	Py_XDECREF(tmp);
+
+	/* add this to memo dict so we won't do it again */
+	rc = PyDict_SetItem(memo, (PyObject *)self, (PyObject *)copy);
+	if (rc == -1) {
+		Py_DECREF(copy);
+		return (NULL);
+	}
+
+	return ((PyObject *)copy);
+}
+
+static PyMethodDef TgtDiskMethods[] = {
+	{
+		.ml_name = "__copy__",
+		.ml_meth = (PyCFunction)TgtDisk_copy,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = NULL
+	}, {
+		.ml_name = "__deepcopy__",
+		.ml_meth = (PyCFunction)TgtDisk_deepcopy,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = NULL
+	}, { NULL } /* Sentinel */
+};
+
+
+static PyMemberDef TgtDiskMembers[] = {
+	{
+		.name = "name",
+		.type = T_STRING,
+		.offset = offsetof(TgtDisk, name),
+		.flags = READONLY, /* only set at __init__() */
+		.doc = "disk name"
+	}, {
+		.name = "controller",
+		.type = T_OBJECT,
+		.offset = offsetof(TgtDisk, controller),
+		.flags = READONLY, /* only set at __init__() */
+		.doc = "disk controller type (a CONTROLLER constant)"
+	}, { NULL } /* Sentinel */
+};
+
+/* structure members that can't be made part of PyMemberDef */
+
+static PyObject *
+TgtDisk_get_geometry(TgtDisk *self, void *closure)
+{
+	PyObject *result = self->geometry;
+	assert(result != NULL);
+	Py_INCREF(result);
+	return (result);
+}
+static int
+TgtDisk_set_geometry(TgtDisk *self, PyObject *value, void *closure)
+{
+	PyObject *tmp = NULL;
+	if (value == NULL || (TgtGeometry_Check(value) == 0)) {
+		PyErr_SetString(PyExc_TypeError,
+		    "\"geometry\" must be a tgt.Geometry object");
+		return (-1);
+	}
+	tmp = self->geometry;
+	self->geometry = value;
+	Py_INCREF(self->geometry);
+	assert(tmp != NULL);
+	Py_DECREF(tmp);
+	return (0);
+}
+PyDoc_STRVAR(TgtDisk_doc_geometry, "tgt.Geometry object describing tgt.Disk");
+
+static PyObject *
+TgtDisk_get_children(TgtDisk *self, void *closure)
+{
+	PyObject *result = self->children;
+	assert(result != NULL);
+	Py_INCREF(result);
+	return (result);
+}
+static int
+TgtDisk_set_children(TgtDisk *self, PyObject *value, void *closure)
+{
+	PyObject *tmp = NULL;
+	if (value == NULL || (PyTuple_Check(value) == 0)) {
+		PyErr_SetString(PyExc_TypeError,
+		    "\"children\" must be a tuple");
+		return (-1);
+	}
+	/* TODO: verify children are all either tgt.Slice or tgt.Partition */
+	tmp = self->children;
+	self->children = value;
+	Py_INCREF(self->children);
+	assert(tmp != NULL);
+	Py_DECREF(tmp);
+	return (0);
+}
+PyDoc_STRVAR(TgtDisk_doc_children,
+	"tuple of tgt.Parttion or tgt.Slice objects");
+
+static PyObject *
+TgtDisk_get_vendor(TgtDisk *self, void *closure)
+{
+	if (self->vendor == NULL) {
+		Py_INCREF(DiskConst.unknown);
+		return (DiskConst.unknown);
+	}
+	return (PyString_FromString(self->vendor));
+}
+PyDoc_STRVAR(TgtDisk_doc_vendor, "disk manufacturer or tgt.Disk.unknown");
+
+static PyObject *
+TgtDisk_get_serialno(TgtDisk *self, void *closure)
+{
+	if (self->serialno == NULL) {
+		Py_INCREF(DiskConst.unknown);
+		return (DiskConst.unknown);
+	}
+	return (PyString_FromString(self->serialno));
+}
+PyDoc_STRVAR(TgtDisk_doc_serialno,
+"manufacturer assigned serialno or tgt.Disk.unknown");
+
+static PyObject *
+TgtDisk_get_blocks(TgtDisk *self, void *closure)
+{
+	return (PyLong_FromLongLong(self->blocks));
+}
+PyDoc_STRVAR(TgtDisk_doc_blocks, "number of blocks (size in blocks)");
+
+#define	BOOL_GETSET(member, doc) \
+static PyObject * \
+TgtDisk_get_##member(TgtDisk *self, void *closure) \
+{ \
+	PyObject *result = (self->member == 1) ? Py_True : Py_False; \
+	Py_INCREF(result); \
+	return (result); \
+} \
+static int \
+TgtDisk_set_##member(TgtDisk *self, PyObject *value, void *closure) \
+{ \
+	if (value == NULL || (PyBool_Check(value) == 0)) { \
+		PyErr_SetString(PyExc_TypeError, "\"" #member "\"" \
+		    "must be a bool"); \
+		return (-1); \
+	} \
+	self->member = (value == Py_True) ? 1 : 0; \
+	return (0); \
+} \
+PyDoc_STRVAR(TgtDisk_doc_##member, doc)
+
+BOOL_GETSET(vtoc, "True if tgt.Disk has VTOC");
+BOOL_GETSET(gpt, "True if tgt.Disk has a GUID Partition Table");
+BOOL_GETSET(fdisk, "True if tgt.Disk has fdisk Partitions");
+BOOL_GETSET(boot, "True if tgt.Disk is a boot disk");
+BOOL_GETSET(removable, "True if tgt.Disk is removable");
+BOOL_GETSET(use_whole, "True if whole disk is to be used for install");
+
+#undef	BOOL_GETSET
+
+static PyObject * \
+TgtDisk__str__(TgtDisk *self) {
+	return (_call_print_method((PyObject*)self, "print_disk"));
+}
+
+static PyGetSetDef TgtDiskGetSets[] = {
+	{
+		.name = "geometry",
+		.get = (getter)TgtDisk_get_geometry,
+		.set = (setter)TgtDisk_set_geometry,
+		.doc = TgtDisk_doc_geometry,
+		.closure = NULL
+	}, {
+		.name = "children",
+		.get = (getter)TgtDisk_get_children,
+		.set = (setter)TgtDisk_set_children,
+		.doc = TgtDisk_doc_children,
+		.closure = NULL
+	}, {
+		.name = "vendor",
+		.get = (getter)TgtDisk_get_vendor,
+		.set = (setter)NULL, /* only set at __init__() */
+		.doc = TgtDisk_doc_vendor,
+		.closure = NULL
+	}, {
+		.name = "serialno",
+		.get = (getter)TgtDisk_get_serialno,
+		.set = (setter)NULL, /* only set at __init__() */
+		.doc = TgtDisk_doc_serialno,
+		.closure = NULL
+	}, {
+		.name = "blocks",
+		.get = (getter)TgtDisk_get_blocks,
+		.set = (setter)NULL, /* only set at __init__() */
+		.doc = TgtDisk_doc_blocks,
+		.closure = NULL
+	}, {
+		.name = "vtoc",
+		.get = (getter)TgtDisk_get_vtoc,
+		.set = (setter)TgtDisk_set_vtoc,
+		.doc = TgtDisk_doc_vtoc,
+		.closure = NULL
+	}, {
+		.name = "gpt",
+		.get = (getter)TgtDisk_get_gpt,
+		.set = (setter)TgtDisk_set_gpt,
+		.doc = TgtDisk_doc_gpt,
+		.closure = NULL
+	}, {
+		.name = "fdisk",
+		.get = (getter)TgtDisk_get_fdisk,
+		.set = (setter)TgtDisk_set_fdisk,
+		.doc = TgtDisk_doc_fdisk,
+		.closure = NULL
+	}, {
+		.name = "boot",
+		.get = (getter)TgtDisk_get_boot,
+		.set = (setter)TgtDisk_set_boot,
+		.doc = TgtDisk_doc_boot,
+		.closure = NULL
+	}, {
+		.name = "removable",
+		.get = (getter)TgtDisk_get_removable,
+		.set = (setter)TgtDisk_set_removable,
+		.doc = TgtDisk_doc_removable,
+		.closure = NULL
+	}, {
+		.name = "use_whole",
+		.get = (getter)TgtDisk_get_use_whole,
+		.set = (setter)TgtDisk_set_use_whole,
+		.doc = TgtDisk_doc_use_whole,
+		.closure = NULL
+	}, { NULL } /* Sentinel */
+};
+
+
+#define	CONSTANT(v, cname, pyname, value) "\t\ttgt.Disk." pyname "\n"
+PyDoc_STRVAR(TgtDiskTypeDoc,
+"tgt.Disk(geometry, name, blocks, controller=tgt.Disk.ATA,\n\
+          vtoc=False, gpt=Fasle, fdisk=False, boot=False,\n\
+          removable=False, vendor=None, serialno=None,\n\
+          use_whole=False) -> tgt.Disk object\n\
+\n\
+A Disk object represents a physical drive in the system.\n\
+\n\
+String constants defined for this class:\n\
+\tCONTROLLER constants:\n"
+CONTROLLER_CONSTANTS
+"\t\ttgt.Disk.UNKNOWN");
+#undef	CONSTANT
+
+
+PyTypeObject TgtDiskType = {
+	PyObject_HEAD_INIT(NULL)
+	.ob_size = 0,
+	.tp_name = "tgt.Disk",
+	.tp_basicsize = sizeof (TgtDisk),
+	.tp_dealloc = (destructor)TgtDisk_Deallocate,
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+	.tp_doc = TgtDiskTypeDoc,
+	.tp_methods = TgtDiskMethods,
+	.tp_members = TgtDiskMembers,
+	.tp_getset = TgtDiskGetSets,
+	.tp_init = (initproc)TgtDisk_Init,
+	.tp_new = TgtDisk_New,
+	.tp_str = (reprfunc)TgtDisk__str__
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/disk.h	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,84 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_DISK_H
+#define	_DISK_H
+#include "Python.h"
+#include "structmember.h"
+
+/* We just need some constants, but it fails unless _FILE_OFFSET_BITS=32 */
+#undef	_FILE_OFFSET_BITS
+#define	_FILE_OFFSET_BITS	32
+#include <libdiskmgt.h>
+#include <sys/dklabel.h>
+
+
+typedef struct {
+	PyObject_HEAD
+	PyObject *geometry;		/* disk geometry */
+	PyObject *children;		/* Partition or Slice Tuple */
+	PyObject *controller;		/* controller type */
+	char *name;			/* disk name */
+	char *vendor;			/* Manufacturer */
+	char *serialno;			/* Manufacturer assigned */
+	uint64_t blocks;		/* nmber of blocks (size in blocks) */
+	uint8_t vtoc		:1;	/* disk label has VTOC */
+	uint8_t gpt		:1;	/* disk has GTP */
+	uint8_t fdisk		:1;	/* disk label has fdisk */
+					/* (implies partitions) */
+	uint8_t boot 		:1;	/* is it a boot disk */
+	uint8_t removable	:1;	/* is it removable */
+	uint8_t use_whole	:1;	/* flag to indicate whole disk use */
+} TgtDisk;
+
+
+/*
+ * Constants
+ * 	v,			cname,	pyname,		value
+ *
+ * The CONTROLLER_CONSTANTS values need to be the values target instantiation
+ * expects (even though they are PyStringObjects).
+ * label is converted from td_disk_label_t to a string when it is requested.
+ *
+ * XXX DM_ seems to be missing SATA and FIREWIRE ?
+ */
+#define	CONTROLLER_CONSTANTS	\
+CONSTANT(DM_CTYPE_ATA,		ata,	"ATA",		DM_CTYPE_ATA)	\
+CONSTANT(DM_CTYPE_SCSI,		scsi,	"SCSI",		DM_CTYPE_SCSI)	\
+CONSTANT(DM_CTYPE_FIBRE,	fibre,	"FIBRE",	DM_CTYPE_FIBRE)	\
+CONSTANT(DM_CTYPE_USB,		usb,	"USB",		DM_CTYPE_USB)
+
+#define	CONSTANT(v, cname, pyname, value) PyObject *cname;
+typedef struct {
+	CONTROLLER_CONSTANTS
+	PyObject *unknown;
+} disk_const;
+#undef CONSTANT
+
+extern disk_const DiskConst;
+
+
+#endif	/* _DISK_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/geometry.c	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,224 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "geometry.h"
+#include "tgt.h"
+#include "boolobject.h"
+#include "td_api.h"
+
+#define	_STRINGIZE(X)	#X
+#define	STRINGIZE(X)	_STRINGIZE(X)
+
+#define	DEFBLKSZ	512
+#define	STR_DEFBLKSZ	STRINGIZE(DEFBLKSZ)
+
+#define	DEFCYLSZ	0
+#define	STR_DEFCYLSZ	STRINGIZE(DEFCYLSZ)
+
+
+/*
+ * Function:    TgtGeometry_Init
+ * Description: Initialize a tgt.Geometry object.
+ * Parameters:
+ *     self:    tgt.Geometry object to fill in
+ *     args:    the arguments given to Python to try to init object
+ *     kwds:    similar to args.
+ * Returns:     None
+ * Scope:       Private
+ *
+ * NOTE: when tgt.discover_target_data() is called this is not used.
+ *       This is for creating a layout without using libtd.so.
+ *       Useful for testing and possibly for target instantiation?
+ */
+static int
+TgtGeometry_Init(TgtGeometry *self, PyObject *args, PyObject *kwds)
+{
+	int rc;
+
+	/* Remember to keep TgtGeometryTypeDoc current with this list */
+	static char *kwlist[] = { "cylsz", "blocksz", NULL };
+
+	/* set default vaule for blocksz */
+	self->blocksz = DEFBLKSZ;
+	self->cylsz = DEFCYLSZ;
+
+	rc = PyArg_ParseTupleAndKeywords(args, kwds, "|II", kwlist,
+		&self->cylsz, &self->blocksz);
+
+	if (!rc)
+		return (-1);
+
+	return (0);
+}
+
+
+/*
+ * Function:    TgtGeometry_New
+ * Description: allocate and assign sensible initial values to a tgt.Geometry.
+ * Parameters:
+ *     type:    type object, do *NOT* assume it is TgtGeometryType!
+ *     args:    ignored, exists to match function prototype.
+ *     kwds:    ignored, exists to match function prototype.
+ * Returns:     None
+ * Scope:       Private
+ */
+static PyObject *
+TgtGeometry_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+	TgtGeometry *self = NULL;
+
+	self = (TgtGeometry *)type->tp_alloc(type, 0);
+	if (self != NULL) {
+		self->blocksz = DEFBLKSZ;
+		self->cylsz = DEFCYLSZ;
+	}
+	return ((PyObject *)self);
+}
+
+
+/*
+ * Function:	TgtGeometry_Deallocate
+ * Description:	Free up a TgtGeometry
+ * Parameters:
+ * 	self:	TgtGeometry to de-allocate
+ * Returns:	Nothing
+ * Scope:	Private
+ */
+static void
+TgtGeometry_Deallocate(TgtGeometry *self)
+{
+	self->ob_type->tp_free((PyObject*)self);
+}
+
+
+static PyObject*
+TgtGeometry_copy(TgtGeometry* self, PyObject* args)
+{
+	if (!PyArg_ParseTuple(args, ":__copy__"))
+		return (NULL);
+
+	/*
+	 * tgt.Geometry is Read Only. Nothing is settable.
+	 * Therefore it is safe to just return another ref to this object.
+	 */
+
+	Py_INCREF(self);
+	return ((PyObject *)self);
+}
+static PyObject*
+TgtGeometry_deepcopy(TgtGeometry* self, PyObject* args)
+{
+	PyObject *memo = NULL;
+
+	if (!PyArg_ParseTuple(args, "O:__deepcopy__", &memo))
+		return (NULL);
+
+	/* Don't need to do any checks */
+	Py_INCREF(self);
+	return ((PyObject *)self);
+}
+
+static PyMethodDef TgtGeometryMethods[] = {
+	{
+		.ml_name = "__copy__",
+		.ml_meth = (PyCFunction)TgtGeometry_copy,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = NULL
+	}, {
+		.ml_name = "__deepcopy__",
+		.ml_meth = (PyCFunction)TgtGeometry_deepcopy,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = NULL
+	}, { NULL } /* Sentinel */
+};
+
+
+static PyMemberDef TgtGeometryMembers[] = {
+	{
+		.name = "blocksz",
+		.type = T_UINT,
+		.offset = offsetof(TgtGeometry, blocksz),
+		.flags = READONLY,
+		.doc = "block size in bytes"
+	}, {
+		.name = "cylsz",
+		.type = T_UINT,
+		.offset = offsetof(TgtGeometry, cylsz),
+		.flags = READONLY,
+		.doc = "cylinder size in blocks"
+	}, { NULL } /* Sentinel */
+};
+
+
+PyDoc_STRVAR(TgtGeometryTypeDoc,
+"tgt.Geometry(cylsz=" STR_DEFCYLSZ ", blocksz=" STR_DEFBLKSZ
+") -> tgt.Geometry object.\n\
+\n\
+A Geometry object represents characteristics of a physical\n\
+drive in the system which are used in size/offset calculations.\n\
+\n\
+The block and cylinder sizes are read-only and can only be set\n\
+when the tgt.Geometry is initialized.\n\
+\n\
+The default \"cylsz\" is almost certainly not what you want and\n\
+will not allow sane calculations of tgt.Partition boundaries.");
+
+
+PyTypeObject TgtGeometryType = {
+	PyObject_HEAD_INIT(NULL)
+	.ob_size = 0,
+	.tp_name = "tgt.Geometry",
+	.tp_basicsize = sizeof (TgtGeometry),
+	.tp_dealloc = (destructor)TgtGeometry_Deallocate,
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+	.tp_doc = TgtGeometryTypeDoc,
+	.tp_methods = TgtGeometryMethods,
+	.tp_members = TgtGeometryMembers,
+	.tp_init = (initproc)TgtGeometry_Init,
+	.tp_new = TgtGeometry_New
+};
+
+/*
+ * The default to initialize tgt.Disk, tgt.Partition, tgt.Slice with. While
+ * block size is often 512, cylinder size varies more.
+ *
+ * Just like Py_None you still have to inc/dec references on TgtGeometryDefault.
+ *
+ * Currently this is just used in tgt.[Disk|Partition|Slice].__new__() to get a
+ * default tgt.Geometry without fear of memory allocation failure and because
+ * they will throw out the geometry in __init__() with a real one. So calling
+ * alloc then init on TgtGeometry is slow and wasteful.
+ *
+ * If the members weren't read only this would require chaning all "setter"
+ * functions to verify the user isn't tryin to modify _TgtGeometryDefault.
+ */
+static TgtGeometry _TgtGeometryDefault = {
+	PyObject_HEAD_INIT(&TgtGeometryType)
+	.blocksz = DEFBLKSZ,
+	.cylsz = DEFCYLSZ
+};
+
+PyObject *TgtGeometryDefault = (PyObject *)&_TgtGeometryDefault;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/geometry.h	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,51 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_GEOMETRY_H
+#define	_GEOMETRY_H
+#include "Python.h"
+#include "structmember.h"
+
+
+/*
+ * The common disk unit is a "block". In order to know the size of a disk,
+ * partition, or slice is, you need to know how big a block is. Often it
+ * will be 512, but it doesn't have to be.
+ *
+ * Cylinders are important for partition boundaries.
+ *
+ * With a tgt.Geometry object you can calculate sizes
+ */
+
+
+typedef struct {
+	PyObject_HEAD
+	uint32_t blocksz;		/* block size in bytes */
+	uint32_t cylsz;			/* Disk cylinder size in blocks */
+} TgtGeometry;
+
+
+#endif	/* _GEOMETRY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/instantiate.c	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,839 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#include <Python.h>
+#include <libnvpair.h>
+#include <sys/types.h>
+#include <sys/systeminfo.h>
+#include "disk.h"
+#include "partition.h"
+#include "geometry.h"
+#include "slice.h"
+#include "zpool.h"
+#include "tgt.h"
+#include "ti_api.h"
+#include <sys/dktp/fdisk.h>
+
+#if defined(i386)
+static int create_fdisk_target(PyObject *self, TgtDisk *disk);
+#endif
+
+static int create_vtoc_target(PyObject *self, TgtDisk *disk,
+    PyObject *create_swap_slice);
+
+#define	ZFS_FS_NUM		1
+#define	TGT_NUMPART		(FD_NUMPART + MAX_EXT_PARTS)
+
+static char *zfs_fs_names[ZFS_FS_NUM] = {"/"};
+
+#if defined(i386)
+/*
+ * create_fdisk_target
+ * Create the nvlist for the creation of an fdisk target via the TI module.
+ * Call ti_create_target to do the creation.
+ * Returns: 0 - Success
+ *	   -1 - Failure
+ */
+/* ARGSUSED */
+static int
+create_fdisk_target(PyObject *self, TgtDisk *disk)
+{
+	nvlist_t	*attrs;
+	int		ret = TI_E_SUCCESS;
+	int		i;
+	int		num_parts, max_part_id;
+	uint8_t		part_ids[TGT_NUMPART], part_active_flags[TGT_NUMPART];
+	uint64_t	part_offsets[TGT_NUMPART], part_sizes[TGT_NUMPART];
+	boolean_t	preserve_array[TGT_NUMPART];
+
+	if (nvlist_alloc(&attrs, TI_TARGET_NVLIST_TYPE, 0) != 0) {
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_uint32(attrs, TI_ATTR_TARGET_TYPE,
+	    TI_TARGET_TYPE_FDISK) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_string(attrs, TI_ATTR_FDISK_DISK_NAME,
+	    disk->name) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	num_parts = PyTuple_GET_SIZE(disk->children);
+	max_part_id = 0;
+	for (i = 0; i < num_parts; i++) {
+		TgtPartition 	*part;
+
+		part = (TgtPartition *)PyTuple_GET_ITEM(disk->children, i);
+		if (part->id > max_part_id)
+			max_part_id = part->id;
+	}
+	if (disk->use_whole || num_parts == 0) {
+		/*
+		 * Do the whole disk, nothing else to do.
+		 */
+		if (nvlist_add_boolean_value(attrs, TI_ATTR_FDISK_WDISK_FL,
+		    B_TRUE) != 0) {
+			nvlist_free(attrs);
+			return (TI_E_PY_NO_SPACE);
+		}
+		ret = ti_create_target(attrs, NULL);
+		nvlist_free(attrs);
+		return (ret);
+	}
+
+	if (nvlist_add_uint16(attrs, TI_ATTR_FDISK_PART_NUM,
+	    max_part_id) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	for (i = 0; i < max_part_id; i++) {
+		part_ids[i] = UNUSED;
+		part_active_flags[i] = part_offsets[i] = part_sizes[i] = 0;
+		preserve_array[i] = B_TRUE;
+	}
+
+	if (num_parts == 0) {
+		/* error */
+		nvlist_free(attrs);
+		return (TI_E_PY_INVALID_ARG);
+	}
+	for (i = 0; i < num_parts; i++) {
+		TgtPartition 	*part;
+		uint64_t	blocks;
+		int		pos;
+		uint32_t	offset;
+
+		part = (TgtPartition *)PyTuple_GET_ITEM(disk->children, i);
+		/*
+		 * Check to see if this is a partition or a slice. We only
+		 * want partitions right now.
+		 */
+		if (!TgtPartition_Check(part)) {
+			continue;
+		}
+
+		blocks =  part->blocks;
+		pos =  part->id - 1;
+		offset = part->offset;
+
+		if (part->modified) {
+			preserve_array[pos] = B_FALSE;
+		}
+
+		part_ids[pos] = part->type;
+		part_active_flags[pos] = 0;
+		part_offsets[pos] = offset;
+		part_sizes[pos] = blocks;
+	}
+
+	if (nvlist_add_uint8_array(attrs, TI_ATTR_FDISK_PART_IDS, part_ids,
+	    max_part_id) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_uint8_array(attrs, TI_ATTR_FDISK_PART_ACTIVE,
+	    part_active_flags, max_part_id) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_uint64_array(attrs, TI_ATTR_FDISK_PART_RSECTS,
+	    part_offsets, max_part_id) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_uint64_array(attrs, TI_ATTR_FDISK_PART_NUMSECTS,
+	    part_sizes, max_part_id) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_boolean_array(attrs, TI_ATTR_FDISK_PART_PRESERVE,
+	    preserve_array, max_part_id) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	ret = ti_create_target(attrs, NULL);
+	nvlist_free(attrs);
+	return (ret);
+}
+#endif
+
+static uint16_t
+slice_1_tag(
+	uint16_t slice_num,
+	uint16_t *slice_nums,
+	uint64_t *slice_size,
+	uint16_t *slice_tags)
+{
+	int i;
+
+	for (i = 0; i < slice_num; i++) {
+		if (slice_nums[i] == 1 && slice_size[i] != 0) {
+			return (slice_tags[i]);
+		}
+	}
+	return (V_UNASSIGNED);
+
+}
+
+/*
+ * create_disk_label
+ * Create the label for the disk.
+ * Call ti_create_target to do the creation.
+ * Returns: Success - libti return code from imm_create_disk_label_target
+ *	    Failure - libti error code from imm_create_disk_label_target or
+ *              TI_E_PY_NO_SPACE
+ */
+/* ARGSUSED */
+static int
+create_disk_label(PyObject *self, TgtDisk *disk)
+{
+	nvlist_t	*attrs;
+	int		ret = TI_E_SUCCESS;
+
+	if (nvlist_alloc(&attrs, TI_TARGET_NVLIST_TYPE, 0) != 0) {
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_uint32(attrs, TI_ATTR_TARGET_TYPE,
+	    TI_TARGET_TYPE_DISK_LABEL) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_string(attrs, TI_ATTR_LABEL_DISK_NAME,
+	    disk->name) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	ret = ti_create_target(attrs, NULL);
+	nvlist_free(attrs);
+	return (ret);
+}
+
+/*
+ * create_vtoc_target
+ * Create the nvlist for the creation of an vtoc target via the TI module.
+ * Call ti_create_target to do the creation.
+ * Returns: 0 - Success
+ *	   -1 - Failure
+ */
+/* ARGSUSED */
+static int
+create_vtoc_target(PyObject *self, TgtDisk *disk, PyObject *create_swap_slice)
+{
+	nvlist_t	*attrs;
+	int		ret = TI_E_SUCCESS;
+	int		num_slices;
+	int		num_children;
+	PyObject	*child;
+	TgtPartition	*part;
+	TgtSlice	*slice;
+	uint16_t	snum;
+	uint16_t	*s_num, *s_tag, *s_flag, tag;
+	uint64_t	*s_start, *s_size;
+	int		i, j;
+	boolean_t	use_whole = B_FALSE;
+
+
+	if (nvlist_alloc(&attrs, TI_TARGET_NVLIST_TYPE, 0) != 0) {
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_uint32(attrs, TI_ATTR_TARGET_TYPE,
+	    TI_TARGET_TYPE_VTOC) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	if (nvlist_add_string(attrs, TI_ATTR_FDISK_DISK_NAME,
+	    disk->name) != 0) {
+		nvlist_free(attrs);
+		return (TI_E_PY_NO_SPACE);
+	}
+
+	/*
+	 * First create the array of slices
+	 */
+	num_children = PyTuple_GET_SIZE(disk->children);
+
+	s_num = s_tag = s_flag = NULL;
+	s_start = s_size = NULL;
+
+	if (((TgtDisk *)disk)->use_whole) {
+		use_whole = B_TRUE;
+	} else {
+		if (num_children == 0) {
+			/*
+			 * conflicting info from the user.
+			 * throw an error.
+			 */
+			nvlist_free(attrs);
+			return (TI_E_PY_INVALID_ARG);
+		}
+	}
+	for (i = 0, snum = 0; i < num_children; i++) {
+		child = PyTuple_GET_ITEM(
+		    disk->children, i);
+		if (!TgtSlice_Check(child)) {
+			/*
+			 * Must be a partition
+			 * Now check for the slices that are on
+			 * partitions.
+			 */
+			part = (TgtPartition *)child;
+			if (part->use_whole) {
+				use_whole = B_TRUE;
+			}
+			num_slices =
+			    PyTuple_GET_SIZE(part->children);
+			if (num_slices == 0) {
+				/* no slices on the partition */
+				continue;
+			}
+			for (j = 0; j < num_slices; j++) {
+				slice = (TgtSlice *)PyTuple_GET_ITEM(
+				    ((TgtPartition *)part)->children, j);
+				if (!TgtSlice_Check(slice)) {
+					continue;
+				}
+				snum++;
+				s_num = realloc(s_num,
+				    snum * sizeof (uint16_t));
+				s_tag = realloc(s_tag,
+				    snum * sizeof (uint16_t));
+				s_flag = realloc(s_flag,
+				    snum * sizeof (uint16_t));
+				s_start = realloc(s_start,
+				    snum * sizeof (uint64_t));
+				s_size = realloc(s_size,
+				    snum * sizeof (uint64_t));
+				if (s_num == NULL || s_tag == NULL ||
+				    s_flag == NULL || s_start == NULL ||
+				    s_size == NULL) {
+				    nvlist_free(attrs);
+					return (TI_E_PY_NO_SPACE);
+				}
+				s_num[snum-1] = slice->number;
+				s_tag[snum-1] = slice->tag;
+				s_flag[snum-1] =
+				    (slice->unmountable & V_UNMNT) |
+				    ((slice->readonly << 4) & V_RONLY);
+				s_start[snum-1] = slice->offset;
+				s_size[snum-1] = slice->blocks;
+
+			}
+			continue;
+		}
+		slice = (TgtSlice *)child;
+		if (slice->blocks == 0) {
+			continue;
+		}
+
+		snum++;
+		/* reallocate memory for another line */
+		s_num = realloc(s_num, snum * sizeof (uint16_t));
+		s_tag = realloc(s_tag, snum * sizeof (uint16_t));
+		s_flag = realloc(s_flag, snum * sizeof (uint16_t));
+		s_start = realloc(s_start, snum * sizeof (uint64_t));
+		s_size = realloc(s_size, snum * sizeof (uint64_t));
+		if (s_num == NULL || s_tag == NULL || s_flag == NULL ||
+		    s_start == NULL || s_size == NULL) {
+			nvlist_free(attrs);
+			return (TI_E_PY_NO_SPACE);
+		}
+
+		s_num[snum-1] = slice->number;
+		s_tag[snum-1] = slice->tag;
+		s_flag[snum-1] = (slice->unmountable & V_UNMNT) |
+		    ((slice->readonly << 4) & V_RONLY);
+		s_start[snum-1] = slice->offset;
+		s_size[snum-1] = slice->blocks;
+	}
+
+
+	if (create_swap_slice == Py_True) {
+		/*
+		 * If slice 1 is in the table, check whether it is already
+		 * marked as a swap slice in VTOC partition flag.
+		 */
+		tag = slice_1_tag(snum, s_num, s_size, s_tag);
+		switch (tag) {
+		case V_SWAP:
+		case NULL:
+			if (nvlist_add_boolean_value(attrs,
+			    TI_ATTR_CREATE_SWAP_SLICE, B_TRUE) != 0) {
+				nvlist_free(attrs);
+				return (TI_E_PY_NO_SPACE);
+			}
+			break;
+		default:
+			/* error message */
+			ret = TI_E_PY_SWAP_INVALID;
+			break;
+		}
+
+	}
+
+	if (use_whole) {
+		if (nvlist_add_boolean_value(attrs,
+		    TI_ATTR_SLICE_DEFAULT_LAYOUT, B_TRUE) != 0) {
+			nvlist_free(attrs);
+			return (TI_E_PY_NO_SPACE);
+		}
+	} else {
+		if (nvlist_add_uint16(attrs, TI_ATTR_SLICE_NUM, snum) != 0) {
+			nvlist_free(attrs);
+			return (TI_E_PY_NO_SPACE);
+		}
+
+		if (nvlist_add_uint16_array(attrs, TI_ATTR_SLICE_PARTS,
+		    s_num, snum) != 0) {
+			nvlist_free(attrs);
+			return (TI_E_PY_NO_SPACE);
+		}
+
+		if (nvlist_add_uint16_array(attrs, TI_ATTR_SLICE_TAGS,
+		    s_tag, snum) != 0) {
+			nvlist_free(attrs);
+			return (TI_E_PY_NO_SPACE);
+		}
+
+		if (nvlist_add_uint16_array(attrs, TI_ATTR_SLICE_FLAGS,
+		    s_flag, snum) != 0) {
+			nvlist_free(attrs);
+			return (TI_E_PY_NO_SPACE);
+		}
+
+		if (nvlist_add_uint64_array(attrs, TI_ATTR_SLICE_1STSECS,
+		    s_start, snum) != 0) {
+			nvlist_free(attrs);
+			return (TI_E_PY_NO_SPACE);
+		}
+
+		if (nvlist_add_uint64_array(attrs, TI_ATTR_SLICE_SIZES,
+		    s_size, snum) != 0) {
+			nvlist_free(attrs);
+			return (TI_E_PY_NO_SPACE);
+		}
+	}
+
+	ret = ti_create_target(attrs, NULL) | ret;
+	nvlist_free(attrs);
+	return (ret);
+}
+
+/*
+ * create_disk_target
+ * Detect if the system is sparc or x86 and create a fdisk or vtoc
+ * target accordingly. If it is a GPT labeled disk on sparc, relabel
+ * it as SMI.
+ * Returns: non-NULL - Success
+ *	    NULL - Failure
+ */
+/* ARGSUSED */
+PyObject *
+create_disk_target(PyObject *self, PyObject *args)
+{
+	int		ret = TI_E_SUCCESS;
+	PyObject	*disk;
+	PyObject	*create_swap_slice;
+
+	/*
+	 * Parse the List input
+	 */
+	if (!PyArg_ParseTuple(args, "O!O", &TgtDiskType, &disk,
+	    &create_swap_slice)) {
+		raise_ti_errcode(ret);
+		return (NULL);
+	}
+
+#if defined(i386)
+	ret = create_fdisk_target(self, (TgtDisk *)disk);
+	if (ret != TI_E_SUCCESS) {
+		raise_ti_errcode(ret);
+		return (NULL);
+	}
+#endif
+
+#if defined(sparc)
+	if (((TgtDisk *)disk)->gpt) {
+		/*
+		 * If we have a GPT disk, we want to label the disk
+		 * as SMI so we can create it as a vtoc target later.
+		 * This is done only for sparc because for x86, GPT is
+		 * handled at the partition level.
+		 */
+		ret = create_disk_label(self, (TgtDisk *)disk);
+		if (ret != TI_E_SUCCESS) {
+			raise_ti_errcode(ret);
+			return (NULL);
+		}
+	}
+#endif
+
+	ret = create_vtoc_target(self, (TgtDisk *)disk, create_swap_slice);
+	if ((ret != TI_E_SUCCESS) && (ret != TI_E_PY_SWAP_INVALID)) {
+		raise_ti_errcode(ret);
+		return (NULL);
+	}
+	return (Py_BuildValue("i", ret));
+}
+
+/*
+ * create_zfs_root_pool
+ * Returns: 0 - Success
+ *	   -1 - Failure
+ */
+/* ARGSUSED */
+PyObject *
+create_zfs_root_pool(PyObject *self, PyObject *args)
+{
+	nvlist_t	*attrs;
+	int		ret;
+	PyObject	*zpool;
+
+	/*
+	 * Parse the List input
+	 */
+	if (!PyArg_ParseTuple(args, "O!", &TgtZpoolType, &zpool)) {
+		raise_ti_errcode(TI_E_PY_INVALID_ARG);
+		return (NULL);
+	}
+
+	if (nvlist_alloc(&attrs, TI_TARGET_NVLIST_TYPE, 0) != 0) {
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_uint32(attrs, TI_ATTR_TARGET_TYPE,
+	    TI_TARGET_TYPE_ZFS_RPOOL) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	/*
+	 * Check for zpool name since we must have it.
+	 */
+	if (((TgtZpool *)zpool)->name == NULL) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_INVALID_ARG);
+		return (NULL);
+	}
+	if (nvlist_add_string(attrs, TI_ATTR_ZFS_RPOOL_NAME,
+	    ((TgtZpool *)zpool)->name) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	/*
+	 * Check for zpool device since we must have it.
+	 */
+	if (((TgtZpool *)zpool)->device == NULL) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_INVALID_ARG);
+		return (NULL);
+	}
+	if (nvlist_add_string(attrs, TI_ATTR_ZFS_RPOOL_DEVICE,
+	    ((TgtZpool *)zpool)->device) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	ret = ti_create_target(attrs, NULL);
+	if (ret != TI_E_SUCCESS) {
+		nvlist_free(attrs);
+		raise_ti_errcode(ret);
+		return (NULL);
+	}
+	nvlist_free(attrs);
+	return (Py_BuildValue("i", TI_E_SUCCESS));
+}
+
+/*
+ * create_zfs_volume
+ * Returns: 0 - Success
+ *	   -1 - Failure
+ */
+/* ARGSUSED */
+PyObject *
+create_zfs_volume(PyObject *self, PyObject *args)
+{
+	nvlist_t	*attrs;
+	PyObject	*zfs_swap, *zfs_dump;
+	uint32_t	swap_size, dump_size;
+	char		*root_pool;
+	uint16_t	vol_num = 0;
+	char		*vol_names[2] = { 0 };
+	uint16_t	vol_types[2] = { 0 };
+	uint32_t	vol_sizes[2] = { 0 };
+	int		ret;
+
+
+	/*
+	 * Parse the List input
+	 */
+	if (!PyArg_ParseTuple(args, "sOiOi", &root_pool, &zfs_swap, &swap_size,
+	    &zfs_dump, &dump_size)) {
+		raise_ti_errcode(TI_E_PY_INVALID_ARG);
+		return (NULL);
+	}
+
+
+	if (nvlist_alloc(&attrs, TI_TARGET_NVLIST_TYPE, 0) != 0) {
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_uint32(attrs, TI_ATTR_TARGET_TYPE,
+	    TI_TARGET_TYPE_ZFS_VOLUME) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_string(attrs, TI_ATTR_ZFS_VOL_POOL_NAME,
+	    root_pool) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (zfs_swap == Py_True) {
+		vol_names[vol_num] = TI_ZFS_VOL_NAME_SWAP;
+		vol_types[vol_num] = TI_ZFS_VOL_TYPE_SWAP;
+		vol_sizes[vol_num] = swap_size;
+		vol_num++;
+	}
+	if (zfs_dump == Py_True) {
+		vol_names[vol_num] = TI_ZFS_VOL_NAME_DUMP;
+		vol_types[vol_num] = TI_ZFS_VOL_TYPE_DUMP;
+		vol_sizes[vol_num] = dump_size;
+		vol_num++;
+	}
+
+	if (nvlist_add_uint16(attrs, TI_ATTR_ZFS_VOL_NUM, vol_num) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_string_array(attrs, TI_ATTR_ZFS_VOL_NAMES, vol_names,
+	    vol_num) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_uint32_array(attrs, TI_ATTR_ZFS_VOL_MB_SIZES,
+	    vol_sizes, vol_num) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_uint16_array(attrs, TI_ATTR_ZFS_VOL_TYPES,
+	    vol_types, vol_num) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	ret = ti_create_target(attrs, NULL);
+	if (ret != TI_E_SUCCESS) {
+		nvlist_free(attrs);
+		raise_ti_errcode(ret);
+		return (NULL);
+	}
+
+	nvlist_free(attrs);
+	return (Py_BuildValue("i", TI_E_SUCCESS));
+}
+
+/*
+ * create_be_target
+ * Returns: 0 - Success
+ *	   -1 - Failure
+ */
+/* ARGSUSED */
+PyObject *
+create_be_target(PyObject *self, PyObject *args)
+{
+	nvlist_t	*attrs;
+	char		*root_pool;
+	char		*installed_root_dir;
+	char		*be_name;
+	PyObject	*dataset_tuple;
+	int		num_datasets;
+	TgtZFSDataset	*dataset;
+	char		**shared_fs_names;
+	int		ret = TI_E_SUCCESS;
+	int		i;
+
+	/*
+	 * Parse the List input
+	 */
+	if (!PyArg_ParseTuple(args, "sssO", &root_pool, &be_name,
+	    &installed_root_dir, &dataset_tuple)) {
+		raise_ti_errcode(TI_E_PY_INVALID_ARG);
+		return (NULL);
+	}
+
+	if (nvlist_alloc(&attrs, TI_TARGET_NVLIST_TYPE, 0) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_uint32(attrs, TI_ATTR_TARGET_TYPE,
+	    TI_TARGET_TYPE_BE) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_string(attrs, TI_ATTR_BE_RPOOL_NAME,
+	    root_pool) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_string(attrs, TI_ATTR_BE_NAME,
+	    be_name) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_string_array(attrs, TI_ATTR_BE_FS_NAMES,
+	    zfs_fs_names, ZFS_FS_NUM) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	num_datasets = PyTuple_GET_SIZE(dataset_tuple);
+	shared_fs_names = malloc(num_datasets * (sizeof (char *)));
+	for (i = 0; i < num_datasets; i++) {
+		dataset = (TgtZFSDataset *)PyTuple_GET_ITEM(dataset_tuple, i);
+		shared_fs_names[i] = strdup(dataset->mountpoint);
+	}
+	if (nvlist_add_string_array(attrs, TI_ATTR_BE_SHARED_FS_NAMES,
+	    shared_fs_names, num_datasets) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_string(attrs, TI_ATTR_BE_MOUNTPOINT,
+	    installed_root_dir) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	ret = ti_create_target(attrs, NULL);
+	if (ret != TI_E_SUCCESS) {
+		nvlist_free(attrs);
+		raise_ti_errcode(ret);
+		return (NULL);
+	}
+
+	nvlist_free(attrs);
+	return (Py_BuildValue("i", TI_E_SUCCESS));
+}
+
+/*
+ * release_zfs_root_pool
+ * Returns: 0 - Success
+ *	   -1 - Failure
+ */
+/* ARGSUSED */
+PyObject *
+release_zfs_root_pool(PyObject *self, PyObject *args)
+{
+	nvlist_t	*attrs;
+	int		ret;
+	PyObject	*zpool;
+
+	/*
+	 * Parse the List input
+	 */
+	if (!PyArg_ParseTuple(args, "O!", &TgtZpoolType, &zpool)) {
+		raise_ti_errcode(TI_E_PY_INVALID_ARG);
+		return (NULL);
+	}
+
+	if (nvlist_alloc(&attrs, TI_TARGET_NVLIST_TYPE, 0) != 0) {
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	if (nvlist_add_uint32(attrs, TI_ATTR_TARGET_TYPE,
+	    TI_TARGET_TYPE_ZFS_RPOOL) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	/*
+	 * Check for zpool name since we must have it.
+	 */
+	if (((TgtZpool *)zpool)->name == NULL) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_INVALID_ARG);
+		return (NULL);
+	}
+	if (nvlist_add_string(attrs, TI_ATTR_ZFS_RPOOL_NAME,
+	    ((TgtZpool *)zpool)->name) != 0) {
+		nvlist_free(attrs);
+		raise_ti_errcode(TI_E_PY_NO_SPACE);
+		return (NULL);
+	}
+
+	ret = ti_release_target(attrs);
+	if (ret != TI_E_SUCCESS) {
+		nvlist_free(attrs);
+		raise_ti_errcode(ret);
+		return (NULL);
+	}
+
+	nvlist_free(attrs);
+	return (Py_BuildValue("i", TI_E_SUCCESS));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/mapfile-vers	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,32 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+# Basic mapfile to hide all symbols but inittgt() which Python expects
+{
+	global:
+		inittgt;
+
+	local:
+		*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/partition.c	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,763 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "geometry.h"
+#include "disk.h"
+#include "partition.h"
+#include "tgt.h"
+#include "td_api.h"
+
+/*
+ * NOTE: libdiskmgmt has labelled partition data incorrectly. We correct it here
+ *       in the Python names. TgtPartition data structure still use the
+ *       libdiskmgmt naming scheme. Here is the conversion:
+ *
+ * libdiskmgmt   | Python | example
+ * --------------+--------+----------------
+ * id            | number | 1
+ * type          | id     | 0xBF (Solaris2)
+ * typetypething | type   | ???  (Primary)
+ */
+
+
+part_const PartConst;
+
+PyTypeObject TgtPartitionType; /* forward declaration */
+
+#define	MAXID (FD_NUMPART + MAX_EXT_PARTS)
+
+/*
+ * Function:	init_partition
+ * Description:	fill in the class data for tgt.Partition.
+ *              This is stored in PartConst and then we make it available
+ *              as data to the class.
+ * Parameters:
+ *     unknown: the shared string "unknown".
+ * Returns:	None
+ * Scope:	Private
+ *
+ * NOTE: You must not call this until after you have called
+ *       PyType_Ready(&TgtPartitionType), as this adds to the Type's dictionary.
+ *
+ *       Well not yet, but it could later.
+ */
+void
+init_partition(PyObject *unknown)
+{
+	int rc;
+	PyObject *v = NULL;
+	PyObject *k = NULL;
+	PartConst.unknown = unknown; /* add the shared constant. */
+	PyObject *dict = PyDict_New();
+
+	/* Add all our unique keys */
+#define	CONSTANT(key, val) \
+	v = PyString_FromString(val); \
+	assert(v != NULL); \
+	k = PyInt_FromLong(key); \
+	assert(k != NULL); \
+	rc = PyDict_SetItem(dict, k, v); \
+	assert(rc == 0); \
+	Py_DECREF(k); \
+	Py_DECREF(v);
+	UNIQUE_PARTITION_TYPE
+#undef	CONSTANT
+
+	/* add non-unique keys */
+#define	CONSTANT(key, val) \
+	k = PyInt_FromLong(key); \
+	assert(k != NULL); \
+	rc = PyDict_SetItem(dict, k, v); \
+	assert(rc == 0); \
+	Py_DECREF(k);
+
+	v = PyString_FromString(TP_EUMEL_ELAN);
+	assert(v != NULL);
+	EUMEL_ELAN_PARTITION_TYPE
+	Py_DECREF(v);
+
+	v = PyString_FromString(TP_NOVEL);
+	assert(v != NULL);
+	NOVEL_PARTITION_TYPE
+	Py_DECREF(v);
+
+	v = PyString_FromString(TP_FAULT_TOLERANT_FAT32);
+	assert(v != NULL);
+	FAULT_TOLERANT_FAT32_PARTITION_TYPE
+	Py_DECREF(v);
+
+	v = PyString_FromString(TP_FREE_FDISK_HDN_DOS_EXT);
+	assert(v != NULL);
+	FREE_FDISK_HDN_DOS_EXT_PARTITION_TYPE
+	Py_DECREF(v);
+
+	v = PyString_FromString(TP_HP_SPEEDSTOR);
+	assert(v != NULL);
+	HP_SPEEDSTOR_PARTITION_TYPE
+	Py_DECREF(v);
+
+	v = PyString_FromString(TP_DRDOS8);
+	assert(v != NULL);
+	DRDOS8_PARTITION_TYPE
+	Py_DECREF(v);
+
+	v = PyString_FromString(TP_SPEEDSTOR);
+	assert(v != NULL);
+	SPEEDSTOR_PARTITION_TYPE
+	Py_DECREF(v);
+
+	v = PyString_FromString(TP_RESERVED);
+	assert(v != NULL);
+	RESERVED_PARTITION_TYPE
+	Py_DECREF(v);
+
+	v = PyString_FromString(TP_UNUSED);
+	assert(v != NULL);
+	UNUSED_PARTITION_TYPE
+	Py_DECREF(v);
+
+	/* For "unknown" we can use our common PyObject */
+	v = unknown;
+	UNKNOWN_PARTITION_TYPE
+	v = NULL;
+	k = NULL;
+#undef	CONSTANT
+
+	PartConst.type = PyDictProxy_New(dict);
+	PyDict_SetItemString(TgtPartitionType.tp_dict, "UNKNOWN", unknown);
+	PyDict_SetItemString(TgtPartitionType.tp_dict, "ID", PartConst.type);
+}
+
+/*
+ * Function:	TgtPartition_Init
+ * Description:	Initialize a tgt.Partition object.
+ * Parameters:
+ *     self:	tgt.Partition object to fill in
+ *     args:	the arguments given to Python to try to init object
+ *     kwds:	similar to args.
+ * Returns:	None
+ * Scope:	Private
+ *
+ * NOTE: when tgt.discover_target_data() is called this is not used.
+ *       This is for creating a layout without using libtd.so.
+ *       Useful for testing and possibly for target instantiation?
+ */
+static int
+TgtPartition_Init(TgtPartition *self, PyObject *args, PyObject *kwds)
+{
+	int rc;
+	TgtGeometry *geometry = NULL;
+	PyObject *active = NULL;
+	PyObject *modified = NULL;
+	PyObject *use_whole = NULL;
+	PyObject *tmp = NULL;
+
+	static char *kwlist[] = {
+		"geometry", "number", "id", "offset", "blocks", "active",
+		"modified", "use_whole", NULL
+	};
+
+	active = Py_False;
+	rc = PyArg_ParseTupleAndKeywords(args, kwds, "O!IHII|O!O!O!", kwlist,
+	    &TgtGeometryType, &geometry, &self->id, &self->type,
+	    &self->offset, &self->blocks, &PyBool_Type, &active,
+	    &PyBool_Type, &modified, &PyBool_Type, &use_whole);
+
+	if (!rc)
+		return (-1);
+
+	tmp = self->geometry;
+	Py_INCREF(geometry);
+	self->geometry = (PyObject *)geometry;
+	Py_XDECREF(tmp);
+
+	/* Minimal validation */
+	if (self->id > MAXID || self->id < 1) {
+		PyErr_Format(PyExc_ValueError,
+		    "tgt.Partition() \"id\" must be 1-%d", MAXID);
+		return (-1);
+	}
+
+	if (self->type > 0xFF) {
+		if (self->type != 0x182) { /* the one special case */
+			PyErr_SetString(PyExc_ValueError,
+			    "tgt.Partition() \"type\" must be between "
+			    "0 and 255 or 386");
+			return (-1);
+		}
+	}
+
+#define	SET_BOOL(nm) self->nm = (nm == Py_True) ? 1 : 0
+	SET_BOOL(active);
+	SET_BOOL(modified);
+	SET_BOOL(use_whole);
+#undef	SET_BOOL
+
+	return (rc);
+}
+
+/*
+ * Function:	TgtPartition_New
+ * Description:	allocate and assign sensible initial values to a tgt.Partition.
+ * Parameters:
+ *     type:	type object, do *NOT* assume it is TgtPartitionType!
+ *     args:	ignored, exists to match function prototype.
+ *     kwds:	ignored, exists to match function prototype.
+ * Returns:	None
+ * Scope:	Private
+ */
+static PyObject *
+TgtPartition_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+	TgtPartition *self = NULL;
+
+	self = (TgtPartition *)type->tp_alloc(type, 0);
+	if (self == NULL)
+		return (NULL); /* sets memory error */
+
+	/* The only thing that can fail is PyTyple_New so do that first */
+	if ((self->children = PyTuple_New(0)) == NULL) {
+		return (NULL);
+	}
+
+	self->geometry = TgtGeometryDefault;
+	Py_INCREF(TgtGeometryDefault);
+	self->offset = self->blocks = 0;
+	self->type = 0;
+	self->id = 0;
+	self->active = self->modified = self->use_whole = 0;
+	self->children = PyTuple_New(0);
+
+	return ((PyObject *)self);
+}
+
+
+/*
+ * Function:	TgtPartition_Deallocate
+ * Description:	Free up a TgtPartition
+ * Parameters:
+ * 	self:	TgtPartition to de-allocate
+ * Returns:	Nothing
+ * Scope:	Private
+ */
+static void
+TgtPartition_Deallocate(TgtPartition *self)
+{
+	Py_XDECREF(self->geometry);
+	Py_XDECREF(self->children);
+	self->ob_type->tp_free((PyObject*)self);
+}
+
+/* XXX Temporarily leave this in, but better implemented in Python */
+static PyObject *
+TgtPartition_type_as_string(TgtPartition *self)
+{
+	/*
+	 * This is far easier to do in Python.
+	 * In fact this method isn't even documented.
+	 * You just have to figure out how to call the equivalent of
+	 * PyDict_GetItem() on a PyDictProxy. Here it is!
+	 */
+	PyObject *key = NULL;
+	PyObject *result = NULL;
+	PyTypeObject *type = PartConst.type->ob_type;
+
+	key = PyInt_FromLong(self->type);
+
+	result = type->tp_as_mapping->mp_subscript(PartConst.type, key);
+	assert(result != NULL);
+	Py_INCREF(result);
+
+	return (result);
+}
+PyDoc_STRVAR(TgtPartition_doc_type_as_string, "string representation of type");
+
+static int
+TgtPartition_copy_common(TgtPartition *orig, TgtPartition *copy)
+{
+	PyObject *tmp = NULL;
+
+	/* Geometry is always shared */
+	tmp = copy->geometry;
+	Py_INCREF(orig->geometry);
+	copy->geometry = orig->geometry;
+	Py_XDECREF(tmp);
+
+#define	SET_MEMBER(member) copy->member = orig->member
+	SET_MEMBER(offset);
+	SET_MEMBER(blocks);
+	SET_MEMBER(type);
+	SET_MEMBER(id);
+	SET_MEMBER(active);
+	SET_MEMBER(modified);
+	SET_MEMBER(use_whole);
+#undef	SET_MEMBER
+
+	return (0);
+}
+
+static PyObject*
+TgtPartition_copy(TgtPartition* self, PyObject* args)
+{
+	PyObject *tmp = NULL;
+	TgtPartition *copy = NULL;
+
+	if (!PyArg_ParseTuple(args, ":__copy__"))
+		return (NULL);
+
+	copy = (TgtPartition *)TgtPartitionType.tp_new(&TgtPartitionType, NULL,
+	    NULL);
+	if (copy == NULL)
+		return (PyErr_NoMemory());
+
+	if (TgtPartition_copy_common(self, copy) != 0) {
+		Py_DECREF(copy);
+		return (NULL);
+	}
+
+	/* for copy we just need references */
+	tmp = copy->children;
+	Py_INCREF(self->children);
+	copy->children = self->children;
+	Py_XDECREF(tmp);
+
+	return ((PyObject *)copy);
+}
+static PyObject*
+TgtPartition_deepcopy(TgtPartition* self, PyObject* args)
+{
+	int rc, idx;
+	PyObject *tmp = NULL;
+	PyObject *children = NULL;
+	PyObject *memo = NULL;
+	TgtPartition *copy = NULL;
+
+	if (!PyArg_ParseTuple(args, "O!:__deepcopy__", &PyDict_Type, &memo))
+		return (NULL);
+
+	/* check and make sure we haven't copied this already. */
+	rc = PyDict_Contains(memo, (PyObject *)self);
+	switch (rc) {
+	case -1: /* error */
+		return (NULL); /* err should be set */
+	case 1:
+		tmp = PyDict_GetItem(memo, (PyObject *)self);
+		Py_INCREF(tmp);
+		return (tmp); /* don't copy again */
+	}
+	assert(rc == 0);
+
+	copy = (TgtPartition *)TgtPartitionType.tp_new(&TgtPartitionType, NULL,
+	    NULL);
+	if (copy == NULL)
+		return (PyErr_NoMemory());
+
+	if (TgtPartition_copy_common(self, copy) != 0) {
+		Py_DECREF(copy);
+		return (NULL);
+	}
+
+	/* need a new children tuple with new children elements of tuple */
+	rc = PyTuple_Size(self->children);
+
+	children = PyTuple_New(rc);
+	for (idx = 0; idx < rc; idx++) {
+		PyObject *oldc, *newc;
+		oldc = PyTuple_GetItem(self->children, idx);
+		/*
+		 * can't assume its tgt.Partition or tgt.Slice, could be a
+		 * subclass.
+		 */
+		newc = PyObject_CallMethod(oldc, "__deepcopy__", "O", memo);
+		if (newc == NULL || PyTuple_SetItem(children, idx, newc) != 0) {
+			Py_XDECREF(newc);
+			Py_DECREF(children);
+			Py_DECREF(copy);
+			return (NULL);
+		}
+	}
+
+	tmp = copy->children;
+	copy->children = children;
+	Py_XDECREF(tmp);
+
+	/* add this to memo dict so we won't do it again */
+	rc = PyDict_SetItem(memo, (PyObject *)self, (PyObject *)copy);
+	if (rc == -1) {
+		Py_DECREF(copy);
+		return (NULL);
+	}
+
+	return ((PyObject *)copy);
+}
+
+static PyMethodDef TgtPartitionMethods[] = {
+	{
+		.ml_name = "id_as_string", /* libdiskmgmt thinks of as type */
+		.ml_meth = (PyCFunction)TgtPartition_type_as_string,
+		.ml_flags = METH_NOARGS,
+		.ml_doc = TgtPartition_doc_type_as_string
+	}, {
+		.ml_name = "__copy__",
+		.ml_meth = (PyCFunction)TgtPartition_copy,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = NULL
+	}, {
+		.ml_name = "__deepcopy__",
+		.ml_meth = (PyCFunction)TgtPartition_deepcopy,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = NULL
+	}, { NULL } /* Sentinel */
+};
+
+
+static PyObject *
+TgtPartition_get_geometry(TgtPartition *self, void *closure)
+{
+	PyObject *result = self->geometry;
+	assert(result != NULL);
+	Py_INCREF(result);
+	return (result);
+}
+static int
+TgtPartition_set_geometry(TgtPartition *self, PyObject *value, void *closure)
+{
+	PyObject *tmp = NULL;
+	if (value == NULL || (TgtGeometry_Check(value) == 0)) {
+		PyErr_SetString(PyExc_TypeError,
+		    "\"geometry\" must be a tgt.Geometry object");
+		return (-1);
+	}
+	tmp = self->geometry;
+	self->geometry = value;
+	Py_INCREF(self->geometry);
+	assert(tmp != NULL);
+	Py_DECREF(tmp);
+	return (0);
+}
+PyDoc_STRVAR(TgtPartition_doc_geometry,
+	"tgt.Geometry object describing tgt.Disk");
+
+static PyObject *
+TgtPartition_get_children(TgtPartition *self, void *closure)
+{
+	PyObject *result = self->children;
+	assert(result != NULL);
+	Py_INCREF(result);
+	return (result);
+}
+static int
+TgtPartition_set_children(TgtPartition *self, PyObject *value, void *closure)
+{
+	PyObject *tmp = NULL;
+	if (value == NULL || (PyTuple_Check(value) == 0)) {
+		PyErr_SetString(PyExc_TypeError,
+		    "children must be a tuple");
+		return (-1);
+	}
+	/* TODO: verify children are all tgt.Slice objects */
+	tmp = self->children;
+	self->children = value;
+	Py_INCREF(self->children);
+	assert(tmp != NULL);
+	Py_DECREF(tmp);
+	return (0);
+}
+PyDoc_STRVAR(TgtPartition_doc_children, "tuple of tgt.Slice objects");
+
+static PyObject *
+TgtPartition_get_offset(TgtPartition *self, void *closure)
+{
+	PyObject *result = PyInt_FromSize_t((size_t)self->offset);
+	if (result == NULL)
+		return (PyErr_NoMemory());
+	return (result);
+}
+static int
+TgtPartition_set_offset(TgtPartition *self, PyObject *value, void *closure)
+{
+	uint32_t newoff;
+	TgtGeometry *geo = (TgtGeometry *)self->geometry;
+
+	assert(geo != NULL);
+
+	if (value == NULL)
+		goto TgtPartition_set_offset_TYPE_ERROR;
+
+	if (PyLong_Check(value)) {
+		newoff = (uint32_t)PyLong_AsUnsignedLong(value);
+	} else {
+		if (PyInt_Check(value)) {
+			newoff = (uint32_t)PyInt_AsLong(value);
+		} else {
+			goto TgtPartition_set_offset_TYPE_ERROR;
+		}
+	}
+
+	self->offset = newoff;
+	return (0);
+
+TgtPartition_set_offset_TYPE_ERROR:
+	PyErr_SetString(PyExc_TypeError, "\"offset\" must be an integer");
+	return (-1);
+}
+PyDoc_STRVAR(TgtPartition_doc_offset, "partition offset in disk blocks");
+
+static PyObject *
+TgtPartition_get_blocks(TgtPartition *self, void *closure)
+{
+	PyObject *result = PyInt_FromSize_t((size_t)self->blocks);
+	if (result == NULL)
+		return (PyErr_NoMemory());
+	return (result);
+}
+static int
+TgtPartition_set_blocks(TgtPartition *self, PyObject *value, void *closure)
+{
+	uint32_t newblk;
+	TgtGeometry *geo = (TgtGeometry *)self->geometry;
+
+	assert(geo != NULL);
+
+	if (value == NULL)
+		goto TgtPartition_set_blocks_TYPE_ERROR;
+
+	if (PyLong_Check(value)) {
+		newblk = (uint32_t)PyLong_AsUnsignedLong(value);
+	} else {
+		if (PyInt_Check(value)) {
+			newblk = (uint32_t)PyInt_AsLong(value);
+		} else {
+			goto TgtPartition_set_blocks_TYPE_ERROR;
+		}
+	}
+
+	self->blocks = newblk;
+	return (0);
+
+TgtPartition_set_blocks_TYPE_ERROR:
+	PyErr_SetString(PyExc_TypeError, "\"blocks\" must be an integer");
+	return (-1);
+}
+PyDoc_STRVAR(TgtPartition_doc_blocks, "partition size in disk blocks");
+
+static PyObject *
+TgtPartition_get_type(TgtPartition *self, void *closure)
+{
+	PyObject *result = PyInt_FromLong((long)self->type);
+	if (result == NULL)
+		return (PyErr_NoMemory());
+	return (result);
+}
+static int
+TgtPartition_set_type(TgtPartition *self, PyObject *value, void *closure)
+{
+	uint16_t newtype;
+
+	if (value == NULL)
+		goto TgtPartition_set_type_TYPE_ERROR;
+
+	if (PyLong_Check(value)) {
+		newtype = (uint16_t)PyLong_AsUnsignedLong(value);
+	} else {
+		if (PyInt_Check(value)) {
+			newtype = (uint16_t)PyInt_AsLong(value);
+		} else {
+			goto TgtPartition_set_type_TYPE_ERROR;
+		}
+	}
+
+	if (newtype > 0xFF) {
+		if (newtype != 0x182) {
+			PyErr_SetString(PyExc_ValueError,
+			    "tgt.Partition() \"type\" must be between "
+			    "0 and 255 or 386");
+			return (-1);
+		}
+	}
+	self->type = newtype;
+	return (0);
+
+TgtPartition_set_type_TYPE_ERROR:
+	PyErr_SetString(PyExc_TypeError,
+	    "\"type\" must be a tgt.Geometry object");
+	return (-1);
+}
+PyDoc_STRVAR(TgtPartition_doc_type, "0-255 or 386, partition type");
+
+
+static PyObject *
+TgtPartition_get_id(TgtPartition *self, void *closure)
+{
+	PyObject *result = PyInt_FromLong((long)self->id);
+	if (result == NULL)
+		return (PyErr_NoMemory());
+	return (result);
+}
+static int
+TgtPartition_set_id(TgtPartition *self, PyObject *value, void *closure)
+{
+	uint8_t newid;
+
+	if (value == NULL)
+		goto TgtPartition_set_id_TYPE_ERROR;
+
+	if (PyLong_Check(value)) {
+		newid = (uint8_t)PyLong_AsUnsignedLong(value);
+	} else {
+		if (PyInt_Check(value)) {
+			newid = (uint8_t)PyInt_AsLong(value);
+		} else {
+			goto TgtPartition_set_id_TYPE_ERROR;
+		}
+	}
+
+	if (newid > MAXID || newid < 1) {
+		PyErr_Format(PyExc_ValueError, "\"number\" must be 1-%d",
+		    MAXID);
+		return (-1);
+	}
+	self->id = newid;
+	return (0);
+
+TgtPartition_set_id_TYPE_ERROR:
+	PyErr_Format(PyExc_ValueError,
+	    "\"number\" must be an integer 1-%d", MAXID);
+	return (-1);
+}
+PyDoc_STRVAR(TgtPartition_doc_id, "fdisk id");
+
+#define	BOOL_GETSET(member, doc) \
+static PyObject * \
+TgtPartition_get_##member(TgtPartition *self, void *closure) \
+{ \
+	PyObject *result = (self->member == 1) ? Py_True : Py_False; \
+	Py_INCREF(result); \
+	return (result); \
+} \
+static int \
+TgtPartition_set_##member(TgtPartition *self, PyObject *value, void *closure) \
+{ \
+	if (value == NULL || (PyBool_Check(value) == 0)) { \
+		PyErr_SetString(PyExc_TypeError, "\"" #member "\"" \
+		    "must be a bool"); \
+		return (-1); \
+	} \
+	self->member = (value == Py_True) ? 1 : 0; \
+	return (0); \
+} \
+PyDoc_STRVAR(TgtPartition_doc_##member, doc)
+
+BOOL_GETSET(active, "True if tgt.Partition is active");
+BOOL_GETSET(modified, "True if tgt.Partition has been modified");
+BOOL_GETSET(use_whole, "True if whole partition is to be used for install");
+
+#undef	BOOL_GETSET
+
+static PyObject * \
+TgtPartition__str__(TgtPartition *self) {
+	return (_call_print_method((PyObject*)self, "print_partition"));
+}
+
+static PyGetSetDef TgtPartitionGetSets[] = {
+	{
+		.name = "geometry",
+		.get = (getter)TgtPartition_get_geometry,
+		.set = (setter)TgtPartition_set_geometry,
+		.doc = TgtPartition_doc_geometry,
+		.closure = NULL
+	}, {
+		.name = "children",
+		.get = (getter)TgtPartition_get_children,
+		.set = (setter)TgtPartition_set_children,
+		.doc = TgtPartition_doc_children,
+		.closure = NULL
+	}, {
+		.name = "offset",
+		.get = (getter)TgtPartition_get_offset,
+		.set = (setter)TgtPartition_set_offset,
+		.doc = TgtPartition_doc_offset,
+		.closure = NULL
+	}, {
+		.name = "blocks",
+		.get = (getter)TgtPartition_get_blocks,
+		.set = (setter)TgtPartition_set_blocks,
+		.doc = TgtPartition_doc_blocks,
+		.closure = NULL
+	}, {
+		.name = "id", /* libdiskmgmt thinks of as type */
+		.get = (getter)TgtPartition_get_type,
+		.set = (setter)TgtPartition_set_type,
+		.doc = TgtPartition_doc_type,
+		.closure = NULL
+	}, {
+		.name = "number", /* libdiskmgmt thinks of as id */
+		.get = (getter)TgtPartition_get_id,
+		.set = (setter)TgtPartition_set_id,
+		.doc = TgtPartition_doc_id,
+		.closure = NULL
+	}, {
+		.name = "active",
+		.get = (getter)TgtPartition_get_active,
+		.set = (setter)TgtPartition_set_active,
+		.doc = TgtPartition_doc_active,
+		.closure = NULL
+	}, {
+		.name = "modified",
+		.get = (getter)TgtPartition_get_modified,
+		.set = (setter)TgtPartition_set_modified,
+		.doc = TgtPartition_doc_modified,
+		.closure = NULL
+	}, {
+		.name = "use_whole",
+		.get = (getter)TgtPartition_get_use_whole,
+		.set = (setter)TgtPartition_set_use_whole,
+		.doc = TgtPartition_doc_use_whole,
+		.closure = NULL
+	}, { NULL } /* Sentinel */
+};
+
+
+PyDoc_STRVAR(TgtPartitionTypeDoc,
+"tgt.Partition(geometry, number, id, offset, blocks, active=False,\n\
+               modified=False, use_whole=False) -> tgt.Partition object");
+
+
+PyTypeObject TgtPartitionType = {
+	PyObject_HEAD_INIT(NULL)
+	.ob_size = 0,
+	.tp_name = "tgt.Partition",
+	.tp_basicsize = sizeof (TgtPartition),
+	.tp_dealloc = (destructor)TgtPartition_Deallocate,
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+	.tp_doc = TgtPartitionTypeDoc,
+	.tp_methods = TgtPartitionMethods,
+	.tp_members = NULL, /* TgtPartitionMembers, */
+	.tp_getset = TgtPartitionGetSets,
+	.tp_init = (initproc)TgtPartition_Init,
+	.tp_new = TgtPartition_New,
+	.tp_str = (reprfunc)TgtPartition__str__
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/partition.h	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,330 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_PARTITION_H
+#define	_PARTITION_H
+#include "Python.h"
+#include "structmember.h"
+#include <sys/dktp/fdisk.h>
+#include <sys/dklabel.h>
+
+/* Why is it libtd uses 32-bit for offset and blocks of partition? */
+typedef struct {
+	PyObject_HEAD
+	PyObject *geometry;		/* TgtGeometry */
+	PyObject *children;		/* Slice Tuple */
+	uint32_t offset;		/* offset of partition in blocks */
+	uint32_t blocks;		/* size in blocks */
+	uint16_t type;			/* 0x0-0xFF or 0x182 partition type */
+	uint8_t id;			/* fdisk id (0-3) */
+	uint8_t active		:1;	/* True if this is active partition */
+	uint8_t modified	:1;	/* True if the user changed partition */
+	uint8_t use_whole	:1;	/* True if installer should use whole */
+					/* partition */
+} TgtPartition;
+
+
+/*
+ * These valuses courtesy of:
+ * http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
+ * and ONs usr/src/cmd/fdisk/fdisk.c
+ *
+ * There is one problem, 0x82 is the original Solaris and is the current
+ * Linux Swap.
+ *
+ * Currently this is a uint8_t value. So to solve our problem we will make the
+ * Linux swap be 0x182. That is it is its true type 0x82 ORed with 0x100.
+ *
+ * This means when creating a type for instantiation, just mask the now 16-bit
+ * value with 0xFF.
+ *
+ * Also it mens legal values are 0-255 and 386.
+ *
+ *
+ * Separate unique and dups into separate macros. This makes our Python
+ * dictionary more space efficient.
+ *
+ * Constants
+ * 	value,	string
+ */
+
+#define	UNIQUE_PARTITION_TYPE				\
+CONSTANT(0x00, "Empty")					\
+CONSTANT(0x01, "FAT12")					\
+CONSTANT(0x02, "XENIX /")				\
+CONSTANT(0x03, "XENIX /usr")				\
+CONSTANT(0x04, "FAT16 (Upto 32M)")			\
+CONSTANT(0x05, "DOS Extended")				\
+CONSTANT(0x06, "FAT16 (>32M, HUGEDOS)")			\
+CONSTANT(0x07, "IFS: NTFS")				\
+CONSTANT(0x08, "AIX Boot/QNX(qny)")			\
+CONSTANT(0x09, "AIX Data/QNX(qnz)")			\
+CONSTANT(0x0A, "OS/2 Boot/Coherent swap")		\
+CONSTANT(0x0B, "WIN95 FAT32(Upto 2047GB)")		\
+CONSTANT(0x0C, "WIN95 FAT32(LBA)")			\
+CONSTANT(0x0E, "WIN95 FAT16(LBA)")			\
+CONSTANT(0x0F, "WIN95 Extended(LBA)")			\
+CONSTANT(0x10, "OPUS")					\
+CONSTANT(0x11, "Hidden FAT12")				\
+CONSTANT(0x12, "Diagnostic")				\
+CONSTANT(0x14, "Hidden FAT16(Upto 32M)")		\
+CONSTANT(0x16, "Hidden FAT16(>=32M)")			\
+CONSTANT(0x17, "Hidden IFS: HPFS")			\
+CONSTANT(0x18, "AST SmartSleep Partition")		\
+CONSTANT(0x19, "Unused/Willowtech Photon")		\
+CONSTANT(0x1B, "Hidden FAT32")				\
+CONSTANT(0x1C, "Hidden FAT32(LBA)")			\
+CONSTANT(0x1E, "Hidden FAT16(LBA)")			\
+CONSTANT(0x20, "Unused/OSF1")				\
+CONSTANT(0x21, "Reserved/FSo2(Oxygen FS)")		\
+CONSTANT(0x22, "Unused/(Oxygen EXT)")			\
+CONSTANT(0x24, "NEC DOS 3.x")				\
+CONSTANT(0x2A, "AtheOS File System")			\
+CONSTANT(0x2B, "SyllableSecure")			\
+CONSTANT(0x32, "NOS")					\
+CONSTANT(0x35, "JFS on OS/2")				\
+CONSTANT(0x38, "THEOS 3.2 2GB")				\
+CONSTANT(0x39, "Plan9/THEOS 4")				\
+CONSTANT(0x3A, "THEOS 4 4GB")				\
+CONSTANT(0x3B, "THEOS 4 Extended")			\
+CONSTANT(0x3C, "PartitionMagic Recovery")		\
+CONSTANT(0x3D, "Hidden NetWare")			\
+CONSTANT(0x40, "Venix 80286")				\
+CONSTANT(0x41, "MINIX/PPC PReP Boot")			\
+CONSTANT(0x42, "Win2K Dynamic Disk/SFS(DOS)")		\
+CONSTANT(0x43, "Linux+DRDOS shared")			\
+CONSTANT(0x44, "GoBack partition")			\
+CONSTANT(0x45, "Boot-US boot manager")			\
+CONSTANT(0x4A, "ALFS/THIN FS for DOS")			\
+CONSTANT(0x4C, "Oberon partition")			\
+CONSTANT(0x4D, "QNX 4,x")				\
+CONSTANT(0x4E, "QNX 4,x 2nd Part")			\
+CONSTANT(0x4F, "QNX 4,x 3rd Part")			\
+CONSTANT(0x50, "OnTrack DM R/O, Lynx RTOS")		\
+CONSTANT(0x51, "OnTrack DM R/W, Novell")		\
+CONSTANT(0x52, "CP/M")					\
+CONSTANT(0x53, "Disk Manager 6.0 Aux3")			\
+CONSTANT(0x54, "Disk Manager 6.0 DDO")			\
+CONSTANT(0x55, "EZ-Drive")				\
+CONSTANT(0x56, "Golden Bow VFeature/AT&T MS-DOS")	\
+CONSTANT(0x57, "DrivePro")				\
+CONSTANT(0x5C, "Priam EDisk")				\
+CONSTANT(0x63, "Unix SysV, Mach, GNU Hurd")		\
+CONSTANT(0x64, "PC-ARMOUR, Netware 286")		\
+CONSTANT(0x65, "Netware 386")				\
+CONSTANT(0x66, "Netware SMS")				\
+CONSTANT(0x69, "Netware NSS")				\
+CONSTANT(0x70, "DiskSecure Multi-Boot")			\
+CONSTANT(0x74, "Scramdisk partition")			\
+CONSTANT(0x75, "IBM PC/IX")				\
+CONSTANT(0x77, "M2FS/M2CS,Netware VNDI")		\
+CONSTANT(0x78, "XOSL FS")				\
+CONSTANT(0x80, "MINIX until 1.4a")			\
+CONSTANT(0x81, "MINIX since 1.4b, early Linux")		\
+CONSTANT(0x82, "Solaris")				\
+CONSTANT(0x83, "Linux native")				\
+CONSTANT(0x84, "OS/2 hidden,Win Hibernation")		\
+CONSTANT(0x85, "Linux extended")			\
+CONSTANT(0x86, "Old Linux RAID,NT FAT16 RAID")		\
+CONSTANT(0x87, "NTFS volume set")			\
+CONSTANT(0x88, "Linux plaintext part table")		\
+CONSTANT(0x8A, "Linux Kernel Partition")		\
+CONSTANT(0x8D, "Free FDISK hidden PDOS FAT12")		\
+CONSTANT(0x8E, "Linux LVM partition")			\
+CONSTANT(0x90, "Free FDISK hidden PDOS FAT16")		\
+CONSTANT(0x92, "Free FDISK hidden FAT16 Large")		\
+CONSTANT(0x93, "Hidden Linux native, Amoeba")		\
+CONSTANT(0x94, "Amoeba Bad Block Table")		\
+CONSTANT(0x95, "MIT EXOPC Native")			\
+CONSTANT(0x97, "Free FDISK hidden PDOS FAT32")		\
+CONSTANT(0x98, "Free FDISK hidden FAT32 LBA")		\
+CONSTANT(0x99, "DCE376 logical drive")			\
+CONSTANT(0x9A, "Free FDISK hidden FAT16 LBA")		\
+CONSTANT(0x9F, "BSD/OS")				\
+CONSTANT(0xA0, "Laptop hibernation")			\
+CONSTANT(0xA1, "Laptop hibernate,HP SpeedStor")		\
+CONSTANT(0xA5, "BSD/386,386BSD,NetBSD,FreeBSD")		\
+CONSTANT(0xA6, "OpenBSD,HP SpeedStor")			\
+CONSTANT(0xA7, "NeXTStep")				\
+CONSTANT(0xA8, "Mac OS-X")				\
+CONSTANT(0xA9, "NetBSD")				\
+CONSTANT(0xAA, "Olivetti FAT12 1.44MB Service")		\
+CONSTANT(0xAB, "Mac OS-X Boot")				\
+CONSTANT(0xAE, "ShagOS filesystem")			\
+CONSTANT(0xAF, "ShagOS swap")				\
+CONSTANT(0xB0, "BootStar Dummy")			\
+CONSTANT(0xB6, "Corrupted FAT16 NT Mirror Set")		\
+CONSTANT(0xB7, "Corrupted NTFS NT Mirror Set")		\
+CONSTANT(0xB8, "Old BSDI BSD/386 swap")			\
+CONSTANT(0xBB, "Boot Wizard hidden")			\
+CONSTANT(0xBE, "Solaris x86 boot")			\
+CONSTANT(0xBF, "Solaris2")				\
+CONSTANT(0xC0, "REAL/32 or Novell DOS secured")		\
+CONSTANT(0xC1, "DRDOS/secured(FAT12)")			\
+CONSTANT(0xC2, "Hidden Linux")				\
+CONSTANT(0xC3, "Hidden Linux swap")			\
+CONSTANT(0xC4, "DRDOS/secured(FAT16,< 32M)")		\
+CONSTANT(0xC5, "DRDOS/secured(Extended)")		\
+CONSTANT(0xC6, "NT corrupted FAT16 volume")		\
+CONSTANT(0xC7, "NT corrupted NTFS volume")		\
+CONSTANT(0xCB, "DRDOS7.04+ secured FAT32(CHS)")		\
+CONSTANT(0xCC, "DRDOS7.04+ secured FAT32(LBA)")		\
+CONSTANT(0xCD, "CTOS Memdump")				\
+CONSTANT(0xCE, "DRDOS7.04+ FAT16X(LBA)")		\
+CONSTANT(0xCF, "DRDOS7.04+ secure EXT DOS(LBA)")	\
+CONSTANT(0xD0, "REAL/32 secure big, MDOS")		\
+CONSTANT(0xD1, "Old MDOS secure FAT12")			\
+CONSTANT(0xD4, "Old MDOS secure FAT16 <32M")		\
+CONSTANT(0xD5, "Old MDOS secure EXT")			\
+CONSTANT(0xD6, "Old MDOS secure FAT16 >=32M")		\
+CONSTANT(0xD8, "CP/M-86")				\
+CONSTANT(0xDA, "Non-FS Data")				\
+CONSTANT(0xDB, "CP/M,Concurrent DOS,CTOS")		\
+CONSTANT(0xDD, "Hidden CTOS memdump")			\
+CONSTANT(0xDE, "Dell PowerEdge utilities(FAT)")		\
+CONSTANT(0xDF, "DG/UX virtual disk manager")		\
+CONSTANT(0xE0, "ST AVFS(STMicroelectronics)")		\
+CONSTANT(0xE1, "SpeedStor 12-bit FAT EXT")		\
+CONSTANT(0xE4, "SpeedStor 16-bit FAT EXT")		\
+CONSTANT(0xE5, "Tandy MSDOS")				\
+CONSTANT(0xE6, "Storage Dimensions SpeedStor")		\
+CONSTANT(0xEB, "BeOS BFS")				\
+CONSTANT(0xEC, "SkyOS SkyFS")				\
+CONSTANT(0xEE, "EFI Header Indicator")			\
+CONSTANT(0xEF, "EFI Filesystem")			\
+CONSTANT(0xF0, "Linux/PA-RISC boot loader")		\
+CONSTANT(0xF2, "DOS 3.3+ secondary")			\
+CONSTANT(0xF3, "SpeedStor Reserved")			\
+CONSTANT(0xF4, "SpeedStor Large")			\
+CONSTANT(0xF5, "Prologue multi-volume")			\
+CONSTANT(0xF9, "pCache")				\
+CONSTANT(0xFA, "Bochs")					\
+CONSTANT(0xFB, "VMware File System")			\
+CONSTANT(0xFC, "VMware swap")				\
+CONSTANT(0xFD, "Linux raid autodetect")			\
+CONSTANT(0xFE, "NT Disk Administrator hidden")		\
+CONSTANT(0xFF, "Xenix Bad Block Table")			\
+CONSTANT(0x182, "Linux swap")
+
+#define	TP_EUMEL_ELAN			"EUMEL/Elan"
+#define	EUMEL_ELAN_PARTITION_TYPE				\
+CONSTANT(0x46, TP_EUMEL_ELAN) CONSTANT(0x47, TP_EUMEL_ELAN)	\
+CONSTANT(0x48, TP_EUMEL_ELAN)
+
+#define	TP_NOVEL			"Novell"
+#define	NOVEL_PARTITION_TYPE					\
+CONSTANT(0x67, TP_NOVEL) CONSTANT(0x68, TP_NOVEL)
+
+#define	TP_FAULT_TOLERANT_FAT32		"Fault Tolerant FAT32 volume"
+#define	FAULT_TOLERANT_FAT32_PARTITION_TYPE			\
+CONSTANT(0x8B, TP_FAULT_TOLERANT_FAT32)				\
+CONSTANT(0x8C, TP_FAULT_TOLERANT_FAT32)
+
+#define	TP_FREE_FDISK_HDN_DOS_EXT	"Free FDISK hidden DOS EXT"
+#define	FREE_FDISK_HDN_DOS_EXT_PARTITION_TYPE			\
+CONSTANT(0x91, "Free FDISK hidden DOS EXT")			\
+CONSTANT(0x9B, "Free FDISK hidden DOS EXT")
+
+#define	TP_HP_SPEEDSTOR			"HP SpeedStor"
+#define	HP_SPEEDSTOR_PARTITION_TYPE				\
+CONSTANT(0xA3, TP_HP_SPEEDSTOR) CONSTANT(0xA4, TP_HP_SPEEDSTOR)	\
+CONSTANT(0xB1, TP_HP_SPEEDSTOR) CONSTANT(0xB3, TP_HP_SPEEDSTOR)	\
+CONSTANT(0xB4, TP_HP_SPEEDSTOR)
+
+#define	TP_DRDOS8			"DRDOS8.0+"
+#define	DRDOS8_PARTITION_TYPE					\
+CONSTANT(0xC8, TP_DRDOS8) CONSTANT(0xC9, TP_DRDOS8)		\
+CONSTANT(0xCA, TP_DRDOS8)
+
+#define	TP_SPEEDSTOR			"SpeedStor"
+#define	SPEEDSTOR_PARTITION_TYPE				\
+CONSTANT(0x61, TP_SPEEDSTOR) CONSTANT(0xE3, TP_SPEEDSTOR)	\
+CONSTANT(0xF1, TP_SPEEDSTOR) CONSTANT(0xF6, TP_SPEEDSTOR)
+
+#define	TP_RESERVED			"reserved"
+#define	RESERVED_PARTITION_TYPE				\
+CONSTANT(0x23, TP_RESERVED) CONSTANT(0x26, TP_RESERVED)	\
+CONSTANT(0x31, TP_RESERVED) CONSTANT(0x33, TP_RESERVED)	\
+CONSTANT(0x34, TP_RESERVED) CONSTANT(0x36, TP_RESERVED)	\
+CONSTANT(0x71, TP_RESERVED) CONSTANT(0x73, TP_RESERVED)	\
+CONSTANT(0x76, TP_RESERVED)
+
+#define	TP_UNUSED			"unused"
+#define	UNUSED_PARTITION_TYPE \
+CONSTANT(0x0D, TP_UNUSED) CONSTANT(0x1D, TP_UNUSED) CONSTANT(0x7E, TP_UNUSED) \
+CONSTANT(0x7F, TP_UNUSED) CONSTANT(0xED, TP_UNUSED) CONSTANT(0xF7, TP_UNUSED)
+
+
+#define	TP_UNKNOWN			"unknown"
+#define	UNKNOWN_PARTITION_TYPE \
+CONSTANT(0x13, TP_UNKNOWN) CONSTANT(0x15, TP_UNKNOWN)	\
+CONSTANT(0x1A, TP_UNKNOWN) CONSTANT(0x1F, TP_UNKNOWN)	\
+CONSTANT(0x25, TP_UNKNOWN) CONSTANT(0x27, TP_UNKNOWN)	\
+CONSTANT(0x28, TP_UNKNOWN) CONSTANT(0x29, TP_UNKNOWN)	\
+CONSTANT(0x2C, TP_UNKNOWN) CONSTANT(0x2D, TP_UNKNOWN)	\
+CONSTANT(0x2E, TP_UNKNOWN) CONSTANT(0x2F, TP_UNKNOWN)	\
+CONSTANT(0x30, TP_UNKNOWN) CONSTANT(0x37, TP_UNKNOWN)	\
+CONSTANT(0x3E, TP_UNKNOWN) CONSTANT(0x3F, TP_UNKNOWN)	\
+CONSTANT(0x49, TP_UNKNOWN) CONSTANT(0x4B, TP_UNKNOWN)	\
+CONSTANT(0x58, TP_UNKNOWN) CONSTANT(0x59, TP_UNKNOWN)	\
+CONSTANT(0x5A, TP_UNKNOWN) CONSTANT(0x5B, TP_UNKNOWN)	\
+CONSTANT(0x5D, TP_UNKNOWN) CONSTANT(0x5E, TP_UNKNOWN)	\
+CONSTANT(0x5F, TP_UNKNOWN) CONSTANT(0x60, TP_UNKNOWN)	\
+CONSTANT(0x62, TP_UNKNOWN) CONSTANT(0x6A, TP_UNKNOWN)	\
+CONSTANT(0x6B, TP_UNKNOWN) CONSTANT(0x6C, TP_UNKNOWN)	\
+CONSTANT(0x6D, TP_UNKNOWN) CONSTANT(0x6E, TP_UNKNOWN)	\
+CONSTANT(0x6F, TP_UNKNOWN) CONSTANT(0x72, TP_UNKNOWN)	\
+CONSTANT(0x79, TP_UNKNOWN) CONSTANT(0x7A, TP_UNKNOWN)	\
+CONSTANT(0x7B, TP_UNKNOWN) CONSTANT(0x7C, TP_UNKNOWN)	\
+CONSTANT(0x7D, TP_UNKNOWN) CONSTANT(0x89, TP_UNKNOWN)	\
+CONSTANT(0x8F, TP_UNKNOWN) CONSTANT(0x96, TP_UNKNOWN)	\
+CONSTANT(0x9C, TP_UNKNOWN) CONSTANT(0x9D, TP_UNKNOWN)	\
+CONSTANT(0x9E, TP_UNKNOWN) CONSTANT(0xA2, TP_UNKNOWN)	\
+CONSTANT(0xAC, TP_UNKNOWN) CONSTANT(0xAD, TP_UNKNOWN)	\
+CONSTANT(0xB2, TP_UNKNOWN) CONSTANT(0xB5, TP_UNKNOWN)	\
+CONSTANT(0xB9, TP_UNKNOWN) CONSTANT(0xBA, TP_UNKNOWN)	\
+CONSTANT(0xBC, TP_UNKNOWN) CONSTANT(0xBD, TP_UNKNOWN)	\
+CONSTANT(0xD2, TP_UNKNOWN) CONSTANT(0xD3, TP_UNKNOWN)	\
+CONSTANT(0xD7, TP_UNKNOWN) CONSTANT(0xD9, TP_UNKNOWN)	\
+CONSTANT(0xDC, TP_UNKNOWN) CONSTANT(0xE2, TP_UNKNOWN)	\
+CONSTANT(0xE7, TP_UNKNOWN) CONSTANT(0xE8, TP_UNKNOWN)	\
+CONSTANT(0xE9, TP_UNKNOWN) CONSTANT(0xEA, TP_UNKNOWN)	\
+CONSTANT(0xF8, TP_UNKNOWN)
+
+
+/*
+ * There are way to many string constants for partition types.
+ * ptype_to_str() does that lookup.
+ */
+typedef struct {
+	PyObject *type; /* a dictionary from CONSTANTs above */
+	PyObject *unknown;
+} part_const;
+
+extern part_const PartConst;
+
+
+#endif /* _PARTITION_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/slice.c	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,818 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "disk.h"
+#include "partition.h"
+#include "slice.h"
+#include "tgt.h"
+#include "td_api.h"
+
+slice_const SliceConst;
+
+PyTypeObject TgtSliceType; /* forward declaration */
+
+#define	_STRINGIZE(X)	#X
+#define	STRINGIZE(X)	_STRINGIZE(X)
+
+#define	MAXNUM		15
+#define	STR_MAXNUM	STRINGIZE(MAXNUM)
+
+/*
+ * Function:	init_slice
+ * Description:	fill in the class data for tgt.Slice.
+ *              This is stored in SliceConst and then we make it available
+ *              as data to the class.
+ * Parameters:
+ *     unknown: the shared string "unknown".
+ * Returns:	None
+ * Scope:	Private
+ *
+ * NOTE: You must not call this until after you have called
+ *       PyType_Ready(&TgtSliceType), as this adds to the Type's dictionary.
+ *
+ *       You should not need to modify this except for a "constant" that is not
+ *       part of SLICE_TAG_CONSTANTS, like "unknown".
+ */
+void
+init_slice(PyObject *unknown)
+{
+	/* These constants are never cleaned */
+#define	CONSTANT(v, cname, pyname, value) \
+	SliceConst.cname = PyString_FromString(value);
+	SLICE_TAG_CONSTANTS
+	SLICE_USED_BY_CONSTANTS
+#undef	CONSTANT
+	SliceConst.unknown = unknown; /* add the shared constant. */
+
+	/*
+	 * Keep in mind dictionaries don't steal a reference to key or value.
+	 * Which is perfect, we have a pointer to them in SliceConst but now
+	 * when the type object is cleaned up their ref count will go to 0
+	 * and they will disappear.
+	 */
+#define	CONSTANT(v, cname, pyname, value) \
+	PyDict_SetItemString(TgtSliceType.tp_dict, pyname, SliceConst.cname);
+	SLICE_TAG_CONSTANTS
+	SLICE_USED_BY_CONSTANTS
+#undef	CONSTANT
+	PyDict_SetItemString(TgtSliceType.tp_dict, "UNKNOWN", unknown);
+}
+
+
+/*
+ * Function:	TgtSlice_Init
+ * Description:	Initialize a tgt.Slice object.
+ * Parameters:
+ *     self:	tgt.Slice object to fill in
+ *     args:	the arguments given to Python to try to init object
+ *     kwds:	similar to args.
+ * Returns:	None
+ * Scope:	Private
+ *
+ * NOTE: when tgt.discover_target_data() is called this is not used.
+ *       This is for creating a layout without using libtd.so.
+ *       Useful for testing and possibly for target instantiation?
+ */
+static int
+TgtSlice_Init(TgtSlice *self, PyObject *args, PyObject *kwds)
+{
+	int rc;
+	char *tag = NULL;
+	char *type = NULL;
+	char *user = NULL;
+	PyObject *geometry = NULL;
+	PyObject *blocks = NULL;
+	PyObject *offset = NULL;
+	PyObject *unmountable = NULL;
+	PyObject *readonly = NULL;
+	PyObject *modified = NULL;
+	PyObject *tmp = NULL;
+
+	static char *kwlist[] = {
+		"geometry", "number", "tag", "type", "offset", "blocks",
+		"user", "unmountable", "readonly", "modified", NULL
+	};
+
+	rc = PyArg_ParseTupleAndKeywords(args, kwds, "O!BssOO|zO!O!O!", kwlist,
+	    &TgtGeometryType, &geometry, &self->number, &tag, &type, &offset,
+	    &blocks, &user, &PyBool_Type, &unmountable, &PyBool_Type,
+	    &readonly, &PyBool_Type, &modified);
+
+	if (!rc)
+		return (-1); /* Raises TypeError */
+
+	tmp = self->geometry;
+	Py_INCREF(geometry);
+	self->geometry = (PyObject *)geometry;
+	Py_XDECREF(tmp);
+
+	/*  between 0 and 15 inclusive */
+	if (self->number < 0 || self->number > MAXNUM) {
+		PyErr_SetString(PyExc_ValueError,
+		    "tgt.Slice() \"id\" must be between 0 and " STR_MAXNUM
+		    " inclusive");
+		return (-1);
+	}
+
+	/* for tag we need to convert string to the right value */
+	while (1) {
+#define		CONSTANT(v, cname, pyname, value) \
+		if (strcmp(tag, value) == 0) { \
+			self->tag = (uint8_t)v; \
+			break; \
+		}
+		SLICE_TAG_CONSTANTS
+#undef		CONSTANT
+		PyErr_SetString(PyExc_ValueError,
+		    "tgt.Slice() \"tag\" must be one of the appropriate "
+		    "class constants");
+		return (-1);
+	}
+
+	/* for user we need to look up the right constant */
+	while (type != NULL) { /* infinite loop if we were given a type */
+#define		CONSTANT(v, cname, pyname, value) \
+		if (strcmp(type, value) == 0) { \
+			self->type = (uint8_t)v; \
+			break; \
+		}
+		SLICE_USED_BY_CONSTANTS
+#undef		CONSTANT
+		PyErr_Format(PyExc_ValueError,
+		    "tgt.Slice() \"type\" must be one of the appropriate "
+		    "class constants, got \"%s\"", type);
+		return (-1);
+	}
+
+	if (user == NULL) {
+		self->user = NULL;
+	} else {
+		self->user = strdup(user);
+	}
+
+	/* Python 2.4 has no scan code for a potentially 64-bit value */
+	if (PyLong_Check(blocks)) {
+		self->blocks = PyLong_AsUnsignedLongLong(blocks);
+	} else {
+		if (PyInt_Check(blocks)) {
+			self->blocks = (uint64_t)PyInt_AsLong(blocks);
+		} else {
+			PyErr_SetString(PyExc_TypeError, "tgt.Slice() "
+			    "\"blocks\" an integer is required");
+			return (-1);
+		}
+	}
+	if (PyLong_Check(offset)) {
+		self->offset = PyLong_AsUnsignedLongLong(offset);
+	} else {
+		if (PyInt_Check(offset)) {
+			self->offset = (uint64_t)PyInt_AsLong(offset);
+		} else {
+			PyErr_SetString(PyExc_TypeError, "tgt.Slice() "
+			    "\"offset\" an integer is required");
+			return (-1);
+		}
+	}
+
+#define	SET_BOOL(nm) self->nm = (nm == Py_True) ? 1 : 0
+	SET_BOOL(unmountable);
+	SET_BOOL(readonly);
+	SET_BOOL(modified);
+#undef	SET_BOOL
+
+	return (rc);
+}
+
+
+/*
+ * Function:	TgtSlice_New
+ * Description:	allocate and assign sensible initial values to a tgt.Slice.
+ * Parameters:
+ *     type:	type object, do *NOT* assume it is TgtSliceType!
+ *     args:	ignored, exists to match function prototype.
+ *     kwds:	ignored, exists to match function prototype.
+ * Returns:	None
+ * Scope:	Private
+ */
+static PyObject *
+TgtSlice_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+	TgtSlice *self = NULL;
+
+	self = (TgtSlice *)type->tp_alloc(type, 0);
+	if (self == NULL)
+		return (NULL); /* sets memory error */
+
+	self->geometry = TgtGeometryDefault;
+	Py_INCREF(TgtGeometryDefault);
+	self->user = self->last_mount = NULL;
+	self->blocks = self->offset = 0;
+	self->number = 0;
+	self->tag = self->type = (uint8_t)-1;
+	self->unmountable = self->readonly = self->modified = 0;
+
+	return ((PyObject *)self);
+}
+
+
+/*
+ * Function:	TgtSlice_Deallocate
+ * Description:	Free up a TgtSlice
+ * Parameters:
+ * 	self:	TgtSlice to de-allocate
+ * Returns:	Nothing
+ * Scope:	Private
+ *
+ * NOTE: Unless you have not followed the MEMBER macros at the top there
+ *       is no reason to alter this function.
+ */
+static void
+TgtSlice_Deallocate(TgtSlice *self)
+{
+	Py_XDECREF(self->geometry);
+	if (self->user != NULL) {
+		free(self->user);
+		self->user = NULL;
+	}
+	if (self->last_mount != NULL) {
+		free(self->last_mount);
+		self->last_mount = NULL;
+	}
+	self->ob_type->tp_free((PyObject*)self);
+}
+
+static int
+TgtSlice_copy_common(TgtSlice *orig, TgtSlice *copy)
+{
+	PyObject *tmp = NULL;
+
+	/* Geometry is always shared */
+	tmp = copy->geometry;
+	Py_INCREF(orig->geometry);
+	copy->geometry = orig->geometry;
+	Py_XDECREF(tmp);
+
+#define	STRCOPY(member) \
+	if (orig->member != NULL) { \
+		copy->member = strdup(orig->member); \
+		if (copy->member == NULL) { \
+			PyErr_NoMemory(); \
+			return (-1); \
+		} \
+	}
+
+	STRCOPY(user);
+	STRCOPY(last_mount);
+#undef	STRCOPY
+
+
+#define	SET_MEMBER(member) copy->member = orig->member
+	SET_MEMBER(offset);
+	SET_MEMBER(blocks);
+	SET_MEMBER(number);
+	SET_MEMBER(tag);
+	SET_MEMBER(type);
+	SET_MEMBER(unmountable);
+	SET_MEMBER(readonly);
+	SET_MEMBER(modified);
+#undef	SET_MEMBER
+
+	return (0);
+}
+
+static PyObject*
+TgtSlice_copy(TgtSlice* self, PyObject* args)
+{
+	TgtSlice *copy = NULL;
+
+	if (!PyArg_ParseTuple(args, ":__copy__"))
+		return (NULL);
+
+	copy = (TgtSlice *)TgtSliceType.tp_new(&TgtSliceType, NULL, NULL);
+	if (copy == NULL)
+		return (PyErr_NoMemory());
+
+	if (TgtSlice_copy_common(self, copy) != 0) {
+		Py_DECREF(copy);
+		return (NULL);
+	}
+
+	return ((PyObject *)copy);
+}
+static PyObject*
+TgtSlice_deepcopy(TgtSlice* self, PyObject* args)
+{
+	int rc;
+	PyObject *memo = NULL;
+	PyObject *tmp = NULL;
+	TgtSlice *copy = NULL;
+
+	if (!PyArg_ParseTuple(args, "O!:__deepcopy__", &PyDict_Type, &memo))
+		return (NULL);
+
+	/* check and make sure we haven't copied this already. */
+	rc = PyDict_Contains(memo, (PyObject *)self);
+	switch (rc) {
+	case -1: /* error */
+		return (NULL); /* err should be set */
+	case 1:
+		tmp = PyDict_GetItem(memo, (PyObject *)self);
+		Py_INCREF(tmp);
+		return (tmp); /* don't copy again */
+	}
+
+	copy = (TgtSlice *)TgtSliceType.tp_new(&TgtSliceType, NULL, NULL);
+	if (copy == NULL)
+		return (PyErr_NoMemory());
+
+
+	if (TgtSlice_copy_common(self, copy) != 0) {
+		Py_DECREF(copy);
+		return (NULL);
+	}
+
+	/* add this to memo dict so we won't do it again */
+	rc = PyDict_SetItem(memo, (PyObject *)self, (PyObject *)copy);
+	if (rc == -1) {
+		Py_DECREF(copy);
+		return (NULL);
+	}
+
+	return ((PyObject *)copy);
+}
+
+static PyMethodDef TgtSliceMethods[] = {
+	{
+		.ml_name = "__copy__",
+		.ml_meth = (PyCFunction)TgtSlice_copy,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = NULL
+	}, {
+		.ml_name = "__deepcopy__",
+		.ml_meth = (PyCFunction)TgtSlice_deepcopy,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = NULL
+	}, { NULL } /* Sentinel */
+};
+
+
+/* All the TgtSliceGetSets */
+static PyObject *
+TgtSlice_get_geometry(TgtSlice *self, void *closure)
+{
+	PyObject *result = self->geometry;
+	assert(result != NULL);
+	Py_INCREF(result);
+	return (result);
+}
+static int
+TgtSlice_set_geometry(TgtSlice *self, PyObject *value, void *closure)
+{
+	PyObject *tmp = NULL;
+	if (value == NULL || (TgtGeometry_Check(value) == 0)) {
+		PyErr_SetString(PyExc_TypeError,
+		    "\"geometry\" must be a tgt.Geometry object");
+		return (-1);
+	}
+	tmp = self->geometry;
+	self->geometry = value;
+	Py_INCREF(self->geometry);
+	assert(tmp != NULL);
+	Py_DECREF(tmp);
+	return (0);
+}
+PyDoc_STRVAR(TgtSlice_doc_geometry, "tgt.Geometry object describing tgt.Disk");
+
+static PyObject *
+TgtSlice_get_user(TgtSlice *self, void *closure)
+{
+	if (self->user == NULL) {
+		Py_INCREF(SliceConst.unknown);
+		return (SliceConst.unknown);
+	}
+	return (PyString_FromString(self->user));
+}
+static int
+TgtSlice_set_user(TgtSlice *self, PyObject *value, void *closure)
+{
+	char *str;
+	uint8_t newtype;
+	if (value == NULL) {
+		/* NULL/None is OK that will become "unknown" */
+		str = NULL;
+	} else {
+		if (PyString_Check(value) == 0) {
+			PyErr_SetString(PyExc_TypeError,
+			    "\"user\" must be a str");
+			return (-1);
+		}
+		str = strdup(PyString_AsString(value));
+		if (str == NULL) {
+			PyErr_NoMemory();
+			return (-1);
+		}
+	}
+
+	if (self->user != NULL)
+		free(self->user);
+	self->user = str;
+	return (0);
+}
+PyDoc_STRVAR(TgtSlice_doc_user, "slice user string or tgt.Slice.UNKNOWN");
+
+static PyObject *
+TgtSlice_get_last_mount(TgtSlice *self, void *closure)
+{
+	if (self->last_mount == NULL) {
+		Py_INCREF(Py_None);
+		return (Py_None);
+	}
+	return (PyString_FromString(self->last_mount));
+}
+static int
+TgtSlice_set_last_mount(TgtSlice *self, PyObject *value, void *closure)
+{
+	char *str;
+	uint8_t newtype;
+	if (value == NULL) {
+		/* NULL/None is OK that will become "None" */
+		str = NULL;
+	} else {
+		if (PyString_Check(value) == 0) {
+			PyErr_SetString(PyExc_TypeError,
+			    "\"last_mount\" must be a str");
+			return (-1);
+		}
+		str = strdup(PyString_AsString(value));
+		if (str == NULL) {
+			PyErr_NoMemory();
+			return (-1);
+		}
+	}
+
+	if (self->last_mount != NULL)
+		free(self->last_mount);
+	self->last_mount = str;
+	return (0);
+}
+PyDoc_STRVAR(TgtSlice_doc_last_mount,
+	"last mountpoint (for UFS slice) or None");
+
+static PyObject *
+TgtSlice_get_offset(TgtSlice *self, void *closure)
+{
+	return (PyLong_FromLongLong(self->offset));
+}
+static int
+TgtSlice_set_offset(TgtSlice *self, PyObject *value, void *closure)
+{
+	uint64_t newoff;
+
+	if (value == NULL)
+		goto TgtSlice_set_offset_TYPE_ERROR;
+
+	if (PyLong_Check(value)) {
+		newoff = (uint64_t)PyLong_AsUnsignedLong(value);
+	} else {
+		if (PyInt_Check(value)) {
+			newoff = (uint64_t)PyInt_AsLong(value);
+		} else {
+			goto TgtSlice_set_offset_TYPE_ERROR;
+		}
+	}
+	self->offset = newoff;
+	return (0);
+
+TgtSlice_set_offset_TYPE_ERROR:
+	PyErr_SetString(PyExc_TypeError, "\"offset\" must be an integer");
+	return (-1);
+}
+PyDoc_STRVAR(TgtSlice_doc_offset, "offset (in blocks)");
+
+static PyObject *
+TgtSlice_get_blocks(TgtSlice *self, void *closure)
+{
+	return (PyLong_FromLongLong(self->blocks));
+}
+static int
+TgtSlice_set_blocks(TgtSlice *self, PyObject *value, void *closure)
+{
+	uint64_t newblk;
+
+	if (value == NULL)
+		goto TgtSlice_set_blocks_TYPE_ERROR;
+
+	if (PyLong_Check(value)) {
+		newblk = (uint64_t)PyLong_AsUnsignedLong(value);
+	} else {
+		if (PyInt_Check(value)) {
+			newblk = (uint64_t)PyInt_AsLong(value);
+		} else {
+			goto TgtSlice_set_blocks_TYPE_ERROR;
+		}
+	}
+	self->blocks = newblk;
+	return (0);
+
+TgtSlice_set_blocks_TYPE_ERROR:
+	PyErr_SetString(PyExc_TypeError, "\"blocks\" must be an integer");
+	return (-1);
+}
+PyDoc_STRVAR(TgtSlice_doc_blocks, "size in blocks");
+
+static PyObject *
+TgtSlice_get_number(TgtSlice *self, void *closure)
+{
+	PyObject *result = PyInt_FromLong((long)self->number);
+	return (result);
+}
+static int
+TgtSlice_set_number(TgtSlice *self, PyObject *value, void *closure)
+{
+	uint8_t newid;
+
+	if (value == NULL)
+		goto TgtSlice_set_id_TYPE_ERROR;
+
+	if (PyLong_Check(value)) {
+		newid = (uint8_t)PyLong_AsUnsignedLong(value);
+	} else {
+		if (PyInt_Check(value)) {
+			newid = (uint8_t)PyInt_AsLong(value);
+		} else {
+			goto TgtSlice_set_id_TYPE_ERROR;
+		}
+	}
+
+	if (newid > MAXNUM) {
+		PyErr_SetString(PyExc_ValueError,
+		    "\"id\" must be 0-" STR_MAXNUM);
+		return (-1);
+	}
+	self->number = newid;
+	return (0);
+
+TgtSlice_set_id_TYPE_ERROR:
+	PyErr_SetString(PyExc_TypeError,
+	    "\"id\" must be an integer 0-" STR_MAXNUM);
+	return (-1);
+}
+PyDoc_STRVAR(TgtSlice_doc_number, "slice number, (0-" STR_MAXNUM ")");
+
+static PyObject *
+TgtSlice_get_tag(TgtSlice *self, void *closure)
+{
+	PyObject *result = NULL;
+
+	switch (self->tag) {
+#define	CONSTANT(v, cname, pyname, value) \
+	case v: \
+		result = SliceConst.cname; \
+		break;
+	SLICE_TAG_CONSTANTS
+#undef	CONSTANT
+	default:
+		result = SliceConst.unknown;
+	}
+	Py_INCREF(result);
+	return (result);
+}
+static int
+TgtSlice_set_tag(TgtSlice *self, PyObject *value, void *closure)
+{
+	char *str;
+	uint8_t newtag;
+	if (value == NULL || (PyString_Check(value) == 0)) {
+		PyErr_SetString(PyExc_TypeError, "\"tag\" must be a str");
+		return (-1);
+	}
+
+	str = PyString_AsString(value);
+	while (1) {
+#define		CONSTANT(v, cname, pyname, value) \
+		if (strcmp(str, value) == 0) { \
+			newtag = (uint8_t)v; \
+			break; \
+		}
+		SLICE_TAG_CONSTANTS
+#undef		CONSTANT
+		PyErr_SetString(PyExc_ValueError,
+		    "\"tag\" must be one of the appropriate class constants");
+		return (-1);
+	}
+	self->tag = newtag;
+
+	return (0);
+}
+PyDoc_STRVAR(TgtSlice_doc_tag, "slice tag (a tgt.Slice TAG constant)");
+
+static PyObject *
+TgtSlice_get_type(TgtSlice *self, void *closure)
+{
+	PyObject *result = NULL;
+
+	switch (self->type) {
+#define	CONSTANT(v, cname, pyname, value) \
+	case v: \
+		result = SliceConst.cname; \
+		break;
+	SLICE_USED_BY_CONSTANTS
+#undef	CONSTANT
+	default:
+		result = SliceConst.unknown;
+	}
+	Py_INCREF(result);
+	return (result);
+}
+static int
+TgtSlice_set_type(TgtSlice *self, PyObject *value, void *closure)
+{
+	char *str;
+	uint8_t newtype;
+	if (value == NULL || (PyString_Check(value) == 0)) {
+		PyErr_SetString(PyExc_TypeError, "\"type\" must be a str");
+		return (-1);
+	}
+
+	str = PyString_AsString(value);
+	while (1) {
+#define		CONSTANT(v, cname, pyname, value) \
+		if (strcmp(str, value) == 0) { \
+			newtype = (uint8_t)v; \
+			break; \
+		}
+		SLICE_USED_BY_CONSTANTS
+#undef		CONSTANT
+		PyErr_SetString(PyExc_ValueError,
+		    "\"type\" must be one of the appropriate class contants");
+		return (-1);
+	}
+	self->type = newtype;
+
+	return (0);
+}
+PyDoc_STRVAR(TgtSlice_doc_type, "slice type (a tgt.Slice TYPE constant)");
+
+#define	BOOL_GETSET(member, doc) \
+static PyObject * \
+TgtSlice_get_##member(TgtSlice *self, void *closure) \
+{ \
+	PyObject *result = (self->member == 1) ? Py_True : Py_False; \
+	Py_INCREF(result); \
+	return (result); \
+} \
+static int \
+TgtSlice_set_##member(TgtSlice *self, PyObject *value, void *closure) \
+{ \
+	if (value == NULL || (PyBool_Check(value) == 0)) { \
+		PyErr_SetString(PyExc_TypeError, "\"" #member "\"" \
+		    "must be a bool"); \
+		return (-1); \
+	} \
+	self->member = (value == Py_True) ? 1 : 0; \
+	return (0); \
+} \
+PyDoc_STRVAR(TgtSlice_doc_##member, doc)
+
+BOOL_GETSET(unmountable, "True if tgt.Slice is unmountable");
+BOOL_GETSET(readonly, "True if tgt.Slice is read only");
+BOOL_GETSET(modified, "True if tgt.Slice has been modified");
+
+#undef	BOOL_GETSET
+
+static PyObject * \
+TgtSlice__str__(TgtSlice *self) {
+	return (_call_print_method((PyObject*)self, "print_slice"));
+}
+
+static PyGetSetDef TgtSliceGetSets[] = {
+	{
+		.name = "geometry",
+		.get = (getter)TgtSlice_get_geometry,
+		.set = (setter)TgtSlice_set_geometry,
+		.doc = TgtSlice_doc_geometry,
+		.closure = NULL
+	}, {
+		.name = "user",
+		.get = (getter)TgtSlice_get_user,
+		.set = (setter)TgtSlice_set_user,
+		.doc = TgtSlice_doc_user,
+		.closure = NULL
+	}, {
+		.name = "last_mount",
+		.get = (getter)TgtSlice_get_last_mount,
+		.set = (setter)TgtSlice_set_last_mount,
+		.doc = TgtSlice_doc_last_mount,
+		.closure = NULL
+	}, {
+		.name = "offset",
+		.get = (getter)TgtSlice_get_offset,
+		.set = (setter)TgtSlice_set_offset,
+		.doc = TgtSlice_doc_offset,
+		.closure = NULL
+	}, {
+		.name = "blocks",
+		.get = (getter)TgtSlice_get_blocks,
+		.set = (setter)TgtSlice_set_blocks,
+		.doc = TgtSlice_doc_blocks,
+		.closure = NULL
+	}, {
+		.name = "number",
+		.get = (getter)TgtSlice_get_number,
+		.set = (setter)TgtSlice_set_number,
+		.doc = TgtSlice_doc_number,
+		.closure = NULL
+	}, {
+		.name = "tag",
+		.get = (getter)TgtSlice_get_tag,
+		.set = (setter)TgtSlice_set_tag,
+		.doc = TgtSlice_doc_tag,
+		.closure = NULL
+	}, {
+		.name = "type",
+		.get = (getter)TgtSlice_get_type,
+		.set = (setter)TgtSlice_set_type,
+		.doc = TgtSlice_doc_type,
+		.closure = NULL
+	}, {
+		.name = "unmountable",
+		.get = (getter)TgtSlice_get_unmountable,
+		.set = (setter)TgtSlice_set_unmountable,
+		.doc = TgtSlice_doc_unmountable,
+		.closure = NULL
+	}, {
+		.name = "readonly",
+		.get = (getter)TgtSlice_get_readonly,
+		.set = (setter)TgtSlice_set_readonly,
+		.doc = TgtSlice_doc_readonly,
+		.closure = NULL
+	}, {
+		.name = "modified",
+		.get = (getter)TgtSlice_get_modified,
+		.set = (setter)TgtSlice_set_modified,
+		.doc = TgtSlice_doc_modified,
+		.closure = NULL
+	}, { NULL } /* Sentinel */
+};
+
+
+/*
+ * TODO keep this comment current!
+ * If you added a MEMBER at the top that should be part of __init__()
+ * then put it in this doc string.
+ */
+#define	CONSTANT(v, cname, pyname, value) "\t\ttgt.Slice." pyname "\n"
+
+PyDoc_STRVAR(TgtSliceTypeDoc,
+"tgt.Slice(geometry, number, tag, type, offset, blocks,\n\
+           user=tgt.Slice.UNKNOWN, unmountable=False, readonly=False,\n\
+           modified=False) -> tgt.Slice object\n\
+\n\
+A Slice object represents a Solaris slice within a Partition object.\n\
+\n\
+There are two groups of string constants defined for this class:\n\
+\tTAG constants (valid for tgt.Slice.tag):\n"
+SLICE_TAG_CONSTANTS
+"\t\ttgt.Slice.UNKNOWN\n\
+\tTYPE constants (valid for tgt.Slice.type):\n"
+SLICE_USED_BY_CONSTANTS
+"\t\ttgt.Slice.UNKNOWN");
+
+PyTypeObject TgtSliceType = {
+	PyObject_HEAD_INIT(NULL)
+	.ob_size = 0,
+	.tp_name = "tgt.Slice",
+	.tp_basicsize = sizeof (TgtSlice),
+	.tp_dealloc = (destructor)TgtSlice_Deallocate,
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+	.tp_doc = TgtSliceTypeDoc,
+	.tp_methods = TgtSliceMethods,
+	.tp_members = NULL, /* TgtSliceMembers, */
+	.tp_getset = TgtSliceGetSets,
+	.tp_init = (initproc)TgtSlice_Init,
+	.tp_new = TgtSlice_New,
+	.tp_str = (reprfunc)TgtSlice__str__
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/slice.h	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,94 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SLICE_H
+#define	_SLICE_H
+#include "Python.h"
+#include "structmember.h"
+#include "td_api.h"
+#include <sys/vtoc.h> /* for V_UNMNT and V_RONLY */
+
+typedef struct {
+	PyObject_HEAD
+	PyObject *geometry;		/* disk geometry */
+	char *user;			/* user of this slice */
+	char *last_mount;		/* last mount point (for UFS) */
+	uint64_t offset;		/* offset in disk blocks */
+	uint64_t blocks;		/* size in disk blocks */
+	uint8_t number;			/* slice number, (0-15) */
+	uint8_t tag;			/* slice tag, mountpoint (sort of) */
+	uint8_t type;			/* "used by" of this slice */
+	uint8_t unmountable	:1;	/* True if slice may not be unmounted */
+	uint8_t readonly	:1;	/* True if slice is read only */
+	uint8_t modified	:1;	/* True if the user changed slice */
+	uint8_t use_whole	:1;	/* True if install should use entire */
+					/* slice */
+} TgtSlice;
+
+
+/*
+ * Constants
+ * 	v,			cname,	pyname,		value
+ */
+#define	SLICE_TAG_CONSTANTS						\
+CONSTANT(V_UNASSIGNED,	unassigned,	"UNASSIGNED",	"unassigned")	\
+CONSTANT(V_BOOT,	boot,		"BOOT",		"boot")		\
+CONSTANT(V_ROOT,	root,		"ROOT",		"root")		\
+CONSTANT(V_SWAP,	swap,		"SWAP",		"swap")		\
+CONSTANT(V_USR,		usr,		"USR",		"usr")		\
+CONSTANT(V_BACKUP,	backup,		"BACKUP",	"backup")	\
+CONSTANT(V_STAND,	stand,		"STAND",	"stand")	\
+CONSTANT(V_VAR,		var,		"VAR",		"var")		\
+CONSTANT(V_HOME,	home,		"HOME",		"home")		\
+CONSTANT(V_ALTSCTR,	altsctr,	"ALTSCTR",	"alternates")	\
+CONSTANT(V_RESERVED,	reserved,	"RESERVED",	"reserved")
+
+#define	SLICE_USED_BY_CONSTANTS						\
+CONSTANT(1,	mount,	"MOUNT",	TD_SLICE_USEDBY_MOUNT)		\
+CONSTANT(2,	svm,	"SVM",		TD_SLICE_USEDBY_SVM)		\
+CONSTANT(3,	lu,	"LU",		TD_SLICE_USEDBY_LU)		\
+CONSTANT(4,	dump,	"DUMP",		TD_SLICE_USEDBY_DUMP)		\
+CONSTANT(5,	vxvm,	"VXVM",		TD_SLICE_USEDBY_VXVM)		\
+CONSTANT(6,	fs,	"FS",		TD_SLICE_USEDBY_FS)		\
+CONSTANT(7, 	vfstab,	"VFSTAB",	TD_SLICE_USEDBY_VSFTAB)		\
+CONSTANT(8,	ezpool,	"EZPOOL",	TD_SLICE_USEDBY_EXPORT_ZPOOL)	\
+CONSTANT(9,	azpool,	"AZPOOL",	TD_SLICE_USEDBY_ACTIVE_ZPOOL)	\
+CONSTANT(10,	szpool,	"SZPOOL",	TD_SLICE_USEDBY_SPARE_ZPOOL)	\
+CONSTANT(11,	czpool,	"CZPOOL",	TD_SLICE_USEDBY_CACHE_ZPOOL)
+
+
+#define	CONSTANT(v, cname, pyname, value) PyObject *cname;
+typedef struct {
+	SLICE_TAG_CONSTANTS
+	SLICE_USED_BY_CONSTANTS
+	PyObject *unknown;
+} slice_const;
+#undef CONSTANT
+
+extern slice_const SliceConst;
+
+
+#endif	/* _SLICE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/tgt.c	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,326 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "tgt.h"
+#include "td_api.h"
+#include "ti_api.h"
+
+/* Our Exception */
+PyObject *TgtError = NULL;
+PyObject *TgtUtilsModule = NULL;
+
+/*
+ * Just the docstring is in this file as the PyDoc_STRVAR macro
+ * declares a static character pointer.
+ */
+PyDoc_STRVAR(discover_target_data_doc,
+"discover_target_data() -> tuple of tgt.Disk objects");
+PyDoc_STRVAR(create_disk_target_doc,
+"create_disk_target() -> int to indicate success or failure");
+PyDoc_STRVAR(create_zfs_root_pool_doc,
+"create_zfs_root_pool() -> int to indicate success or failure");
+PyDoc_STRVAR(create_zfs_volume_doc,
+"create_zfs_volume() -> int to indicate success or failure");
+PyDoc_STRVAR(create_be_target_doc,
+"create_be_target() -> int to indicate success or failure");
+PyDoc_STRVAR(release_zfs_root_pool_doc,
+"release_zfs_root_pool() -> int to indicate success or failure");
+
+static PyMethodDef TgtMethods[] = {
+	{
+		.ml_name = "discover_target_data",
+		.ml_meth = (PyCFunction)discover_target_data,
+		.ml_flags = METH_NOARGS,
+		.ml_doc = discover_target_data_doc
+	},
+	{
+		.ml_name = "create_disk_target",
+		.ml_meth = (PyCFunction)create_disk_target,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = create_disk_target_doc
+	},
+	{
+		.ml_name = "create_zfs_root_pool",
+		.ml_meth = (PyCFunction)create_zfs_root_pool,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = create_zfs_root_pool_doc
+	},
+	{
+		.ml_name = "release_zfs_root_pool",
+		.ml_meth = (PyCFunction)release_zfs_root_pool,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = release_zfs_root_pool_doc
+	},
+	{
+		.ml_name = "create_zfs_volume",
+		.ml_meth = (PyCFunction)create_zfs_volume,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = create_zfs_volume_doc
+	},
+	{
+		.ml_name = "create_be_target",
+		.ml_meth = (PyCFunction)create_be_target,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = create_be_target_doc
+	}, { NULL }  /* Sentinel */
+};
+
+
+/*
+ * Function:	raise_td_errcode
+ * Description:	based on td_errno_t raise appropriate Python error.
+ * Parameters:	code
+ * Returns:	None
+ * Scope:	Public
+ */
+void
+raise_td_errcode(void)
+{
+	switch (td_get_errno()) {
+	case TD_E_SUCCESS:
+	case TD_E_END:		/* end of enumerated list */
+		break;
+	case TD_E_MEMORY:	/* memory allocation failure */
+		PyErr_NoMemory();
+		break;
+	case TD_E_NO_DEVICE:	/* no device for specified name */
+		PyErr_SetString(TgtError, "No device for specified name");
+		break;
+	case TD_E_NO_OBJECT:	/* specified object does not exist */
+		PyErr_SetString(TgtError, "Specified object does not exist");
+		break;
+	case TD_E_INVALID_ARG:	/* invalid argument passed */
+		/* We should ensure this doesn't happen */
+		PyErr_SetString(PyExc_TypeError, "Invalid argument passed");
+		break;
+	case TD_E_THREAD_CREATE: /* no resources for thread */
+		PyErr_NoMemory();
+		break;
+	case TD_E_SEMAPHORE:	/* error on semaphore */
+	case TD_E_MNTTAB:	/* error on open of mnttab */
+		PyErr_SetString(TgtError, "No device for specified name");
+		break;
+	default:
+		/* header changed and we missed it if this happens */
+		PyErr_SetString(TgtError, "unknown td_errno_t code");
+		break;
+	}
+}
+/*
+ * Function:	raise_ti_errcode
+ * Description:	based on ti_errno_t raise appropriate Python error.
+ * Parameters:	code
+ * Returns:	None
+ * Scope:	Public
+ */
+void
+raise_ti_errcode(int ti_errno)
+{
+	switch (ti_errno) {
+	case TI_E_SUCCESS:
+	case TI_E_INVALID_FDISK_ATTR:	/* fdisk set of attributes invalid */
+		PyErr_SetString(TgtError, "fdisk set of attributes invalid");
+		break;
+	case TI_E_FDISK_FAILED:		/* fdisk part of TI failed */
+		PyErr_SetString(TgtError, "fdisk part of TI failed");
+		break;
+	case TI_E_UNMOUNT_FAILED:	/* freeing target media failed */
+		PyErr_SetString(TgtError, "freeing target media failed");
+		break;
+	case TI_E_INVALID_VTOC_ATTR:	/* VTOC set of attributes invalid */
+		PyErr_SetString(TgtError, "VTOC set of attributes invalid");
+		break;
+	case TI_E_DISK_LABEL_FAILED:	/* disk label failed */
+		PyErr_SetString(PyExc_TypeError, "disk label failed");
+		break;
+	case TI_E_VTOC_FAILED: 		/* VTOC part of TI failed */
+		PyErr_SetString(PyExc_TypeError, "VTOC part of TI failed");
+		break;
+	case TI_E_INVALID_ZFS_ATTR:	/* ZFS set of attributes invalid */
+		PyErr_SetString(PyExc_TypeError,
+		    "ZFS set of attributes invalid");
+		break;
+	case TI_E_ZFS_FAILED:		/* ZFS part of TI failed */
+		PyErr_SetString(PyExc_TypeError, "ZFS part of TI failed");
+		break;
+	case TI_E_INVALID_BE_ATTR:	/* BE set of attributes invalid */
+		PyErr_SetString(PyExc_TypeError,
+		    "BE set of attributes invalid");
+		break;
+	case TI_E_BE_FAILED:		/* BE part of TI failed */
+		PyErr_SetString(PyExc_TypeError, "BE part of TI failed");
+		break;
+	case TI_E_REP_FAILED:		/* progress report failed */
+		PyErr_SetString(PyExc_TypeError, "progress report failed");
+		break;
+	case TI_E_TARGET_UNKNOWN:	/* unknown target type */
+		PyErr_SetString(PyExc_TypeError, "unknown target type");
+		break;
+	case TI_E_TARGET_NOT_SUPPORTED:	/* unsupported target type */
+		PyErr_SetString(PyExc_TypeError, "unsupported target type");
+		break;
+	case TI_E_INVALID_RAMDISK_ATTR:
+		PyErr_SetString(PyExc_TypeError, "Invalid ramdisk attribute");
+		break;
+	case TI_E_RAMDISK_MKFILE_FAILED:
+		PyErr_SetString(PyExc_TypeError, "ramdisk mkfile failed");
+		break;
+	case TI_E_RAMDISK_LOFIADM_FAILED:
+		PyErr_SetString(PyExc_TypeError, "ramdisk lofiadm failed");
+		break;
+	case TI_E_NEWFS_FAILED:
+		PyErr_SetString(PyExc_TypeError, "newfs failed");
+		break;
+	case TI_E_MKDIR_FAILED:
+		PyErr_SetString(PyExc_TypeError, "mkdir failed");
+		break;
+	case TI_E_MOUNT_FAILED:
+		PyErr_SetString(PyExc_TypeError, "mount failed");
+		break;
+	case TI_E_RMDIR_FAILED:
+		PyErr_SetString(PyExc_TypeError, "rmdir failed");
+		break;
+	case TI_E_PY_INVALID_ARG:	/* invalid arg in Python interface */
+		PyErr_SetString(PyExc_TypeError,
+		    "invalid arg in Python interface");
+		break;
+	case TI_E_PY_NO_SPACE:		/* no space error in Python interface */
+		PyErr_SetString(PyExc_TypeError,
+		    "no space error in Python interface");
+		break;
+	default:
+		/* header changed and we missed it if this happens */
+		PyErr_SetString(TgtError, "unknown ti_errno_t code");
+		break;
+	}
+}
+
+
+PyDoc_STRVAR(TgtDoc,
+"This module provides tgt.Disk, tgt.Partition, and tgt.Slice types.");
+
+#ifndef	PyMODINIT_FUNC
+#define	PyMODINIT_FUNC void
+#endif	/* PyMODINIT_FUNC */
+PyMODINIT_FUNC
+inittgt(void)
+{
+	PyObject *module = NULL;
+	PyObject *unknown = NULL;
+
+	/* The type objects provided */
+	if (PyType_Ready(&TgtGeometryType) < 0)
+		return;
+	if (PyType_Ready(&TgtDiskType) < 0)
+		return;
+	if (PyType_Ready(&TgtPartitionType) < 0)
+		return;
+	if (PyType_Ready(&TgtSliceType) < 0)
+		return;
+	if (PyType_Ready(&TgtZpoolType) < 0)
+		return;
+	if (PyType_Ready(&TgtZFSDatasetType) < 0)
+		return;
+
+	module = Py_InitModule3("tgt", TgtMethods, TgtDoc);
+	if (module == NULL)
+		return;
+
+
+	Py_INCREF(&TgtGeometryType);
+	PyModule_AddObject(module, "Geometry", (PyObject *)&TgtGeometryType);
+	Py_INCREF(&TgtDiskType);
+	PyModule_AddObject(module, "Disk", (PyObject *)&TgtDiskType);
+	Py_INCREF(&TgtPartitionType);
+	PyModule_AddObject(module, "Partition", (PyObject *)&TgtPartitionType);
+	Py_INCREF(&TgtSliceType);
+	PyModule_AddObject(module, "Slice", (PyObject *)&TgtSliceType);
+	Py_INCREF(&TgtZpoolType);
+	PyModule_AddObject(module, "Zpool", (PyObject *)&TgtZpoolType);
+	Py_INCREF(&TgtZFSDatasetType);
+	PyModule_AddObject(module, "ZFSDataset",
+	    (PyObject *)&TgtZFSDatasetType);
+
+	TgtError = PyErr_NewException("tgt.TgtError", NULL, NULL);
+	PyModule_AddObject(module, "TgtError", TgtError);
+
+	/* Initialize each type object. */
+	unknown = PyString_FromString("unknown");
+	init_disk(unknown);
+	init_partition(unknown);
+	init_slice(unknown);
+}
+
+PyObject *retrieve_tgt_utils_module() {
+	if (TgtUtilsModule == NULL) {
+		TgtUtilsModule = PyImport_ImportModule(TGT_UTILS);
+	}
+	return (TgtUtilsModule);
+}
+
+
+PyObject *_call_print_method(PyObject *self, const char *method_name) {
+	PyObject *tgt_utils = NULL;
+	PyObject *print_method = NULL;
+	PyObject *args = NULL;
+	PyObject *obj_as_string = NULL;
+
+	tgt_utils = retrieve_tgt_utils_module();
+
+	if (tgt_utils == NULL) {
+		PyErr_Format(PyExc_ImportError, "Could not import %s",
+		    TGT_UTILS);
+		return (NULL);
+	}
+
+	if (PyObject_HasAttrString(tgt_utils, method_name) != 1) {
+		PyErr_Format(PyExc_NameError,
+		    "'%s' not in %s", method_name, TGT_UTILS);
+		return (NULL);
+	}
+
+	print_method = PyObject_GetAttrString(tgt_utils, method_name);
+	if (PyCallable_Check(print_method) != 1) {
+		PyErr_Format(PyExc_TypeError, "'%s' not a callable object",
+		    method_name);
+		goto done;
+	}
+
+	args = PyTuple_Pack(1, self);
+
+	if (args == NULL) {
+		PyErr_NoMemory();
+		goto done;
+	}
+
+	obj_as_string = PyObject_Call(print_method, args, NULL);
+
+done:
+	Py_XDECREF(args);
+	Py_XDECREF(print_method);
+
+	return (obj_as_string);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/tgt.h	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,79 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_TGT_MODULE_H
+#define	_TGT_MODULE_H
+#include "Python.h"
+#include "structmember.h"
+#include <libnvpair.h>
+
+#define	TGT_UTILS "osol_install.tgt_utils"
+
+extern void	raise_td_errcode(void);
+extern void	raise_ti_errcode(int);
+extern PyObject	*discover_target_data(void);
+extern PyObject	*create_disk_target(PyObject *self, PyObject *args);
+extern PyObject	*create_zfs_root_pool(PyObject *self, PyObject *args);
+extern PyObject	*create_zfs_volume(PyObject *self, PyObject *args);
+extern PyObject	*create_be_target(PyObject *self, PyObject *args);
+extern PyObject	*release_zfs_root_pool(PyObject *self, PyObject *args);
+extern PyObject *retrieve_tgt_utils_module();
+extern PyObject *_call_print_method(PyObject *self, const char *method_name);
+
+extern void	init_disk(PyObject *);
+extern void	init_partition(PyObject *);
+extern void	init_slice(PyObject *);
+extern void	init_zpool(PyObject *);
+extern void	init_zfsdataset(PyObject *);
+
+extern int	TgtDisk_add_child(PyObject *, PyObject *);
+extern int	TgtPartition_add_child(PyObject *, PyObject *);
+
+extern PyTypeObject TgtGeometryType;
+#define	TgtGeometry_Check(op) PyObject_TypeCheck(op, &TgtGeometryType)
+#define	TgtGeometry_CheckExact(op) ((op)->ob_type == &TgtGeometryType)
+
+extern PyTypeObject TgtDiskType;
+#define	TgtDisk_Check(op) PyObject_TypeCheck(op, &TgtDiskType)
+#define	TgtDisk_CheckExact(op) ((op)->ob_type == &TgtDiskType)
+
+extern PyTypeObject TgtPartitionType;
+#define	TgtPartition_Check(op) PyObject_TypeCheck(op, &TgtPartitionType)
+#define	TgtPartition_CheckExact(op) ((op)->ob_type == &TgtPartitionType)
+
+extern PyTypeObject TgtSliceType;
+#define	TgtSlice_Check(op) PyObject_TypeCheck(op, &TgtSliceType)
+#define	TgtSlice_CheckExact(op) ((op)->ob_type == &TgtSliceType)
+
+extern PyTypeObject TgtZpoolType;
+#define	TgtZpool_Check(op) PyObject_TypeCheck(op, &TgtZpoolType)
+
+extern PyTypeObject TgtZFSDatasetType;
+#define	TgtZFSDataset_Check(op) PyObject_TypeCheck(op, &TgtZFSDatasetType)
+
+extern PyObject *TgtGeometryDefault;
+
+#endif /* _TGT_MODULE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/tgt_utils.py	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,115 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+'''
+Utility functions written in Python. Intended for use by the tgt module C code,
+so that additional functions of tgt.* objects can be written in Python.
+'''
+
+import osol_install.tgt as tgt
+
+
+def print_disk(tgt_disk, depth=0):
+    '''Print out a tgt.Disk in a legible manner.
+    This function is called by tgt.Disk.__str__
+    
+    '''
+    tabs = "\t" * depth
+    result = []
+    result.append("%s--- Disk (%s) ---" % (tabs, tgt_disk.name))
+    result.append("%sFdisk:VTOC:GPT" % tabs)
+    result.append("%s%s:%s:%s" %
+                  (tabs, tgt_disk.fdisk, tgt_disk.vtoc, tgt_disk.gpt))
+    result.append("%sBlocks: %s (blocksz=%s)" %
+                  (tabs, tgt_disk.blocks, tgt_disk.geometry.blocksz))
+    result.append("%sSize: %s GB" %
+                  (tabs, tgt_disk.blocks * tgt_disk.geometry.blocksz / 1024**3))
+    if tgt_disk.children:
+        if isinstance(tgt_disk.children[0], tgt.Partition):
+            print_fn = print_partition
+        else:
+            print_fn = print_slice
+        for child in tgt_disk.children:
+            result.append(print_fn(child, depth=1))
+    return "\n".join(result)
+
+
+def print_partition(tgt_part, depth=0):
+    '''Print out a tgt.Partition in a legible manner.
+    This function is called by tgt.Partition.__str__
+    
+    '''
+    tabs = "\t" * depth
+    result = []
+    result.append("%s--- Partition (%s) ---" % (tabs, tgt_part.number))
+    result.append("%sType: %s" % (tabs, tgt_part.id_as_string()))
+    result.append("%sOffset: %s (%s GB)" %
+                  (tabs, tgt_part.offset,
+                   tgt_part.offset * tgt_part.geometry.blocksz / 1024**3))
+    result.append("%sBlocks: %s (%s GB)" %
+                  (tabs, tgt_part.blocks,
+                   tgt_part.blocks * tgt_part.geometry.blocksz / 1024**3))
+    result.append("%sActive:%s" % (tabs, tgt_part.active))
+    for child in tgt_part.children:
+        result.append(print_slice(child, depth=(depth + 1)))
+    return "\n".join(result)
+
+
+def print_slice(tgt_slice, depth=0):
+    '''Print out a tgt.Slice in a legible manner.
+    This function is called by tgt.Slice.__str__
+    
+    '''
+    tabs = "\t" * depth
+    result = []
+    result.append("%s--- Slice (%s) ---" % (tabs, tgt_slice.number))
+    result.append("%sType: %s" % (tabs, tgt_slice.type))
+    result.append("%sUser: %s" % (tabs, tgt_slice.user))
+    result.append("%sOffset: %s (%s GB)" %
+                  (tabs, tgt_slice.offset,
+                   tgt_slice.offset * tgt_slice.geometry.blocksz / 1024**3))
+    result.append("%sBlocks: %s (%s GB)" %
+                  (tabs, tgt_slice.blocks,
+                   tgt_slice.blocks * tgt_slice.geometry.blocksz / 1024**3))
+    
+    return "\n".join(result)
+
+
+def print_all_disks(disks=None):
+    ''' Print debugging information for all tgt disks
+        
+        Args: 
+            disks: A list of tgt disk objects. If not specified,
+                   run tgt.discover_target_data() and print out
+                   all found disks
+
+    '''
+
+    if disks is None:
+        disks = tgt.discover_target_data()
+    for disk in disks:
+        print str(disk)
+
+
+if __name__ == '__main__':
+    print_all_disks()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/zpool.c	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,384 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "zpool.h"
+#include "tgt.h"
+#include "boolobject.h"
+
+
+PyTypeObject TgtZpoolType; /* forward declaration */
+PyTypeObject TgtZFSDatasetType; /* forward declaration */
+
+/*
+ * Function:    TgtZFSDataset_Init
+ * Description: Initialize a tgt.ZFSDataset object.
+ * Parameters:
+ *     self:    tgt.ZFSDataset object to fill in
+ *     args:    the arguments given to Python to try to init object
+ *     kwds:    similar to args.
+ * Returns:     None
+ * Scope:       Private
+ *
+ */
+static int
+TgtZFSDataset_Init(TgtZFSDataset *self, PyObject *args, PyObject *kwds)
+{
+	int rc;
+	char *name = NULL;
+	PyObject *zfs_swap;
+	PyObject *zfs_dump;
+	char *mountpoint = NULL;
+	int swap_size, dump_size;
+	char *be_name = NULL;
+
+	static char *kwlist[] = {
+		"name", "mountpoint", "be_name", "zfs_swap", "swap_size",
+		"zfs_dump", "dump_size", NULL
+	};
+
+	/*
+	 * Set default values for unrequired arguments.
+	 */
+	name = mountpoint = be_name = NULL;
+	zfs_swap = zfs_dump = Py_False;
+	swap_size = 0;
+	dump_size = 0;
+
+	rc = PyArg_ParseTupleAndKeywords(args, kwds, "|sssOiOi", kwlist,
+	    &name, &mountpoint, &be_name, &zfs_swap, &swap_size, &zfs_dump,
+	    &dump_size);
+
+	if (!rc) {
+		PyErr_SetString(PyExc_TypeError,
+		    "tgt.ZFSDataset() Error parsing the arguments");
+		return (-1);
+	}
+
+	/*
+	 * If name and mountpoint are specified, then zfs_swap or zfs_dump
+	 * shouldn't be.
+	 */
+	if (name != NULL && mountpoint != NULL) {
+		if (zfs_swap == Py_True || zfs_dump == Py_True) {
+			PyErr_SetString(PyExc_TypeError,
+			    "tgt.ZFSDataset() \"name\" and \"mountpoint\" are "
+			    "mutually exclusive with zfs_swap and zfs_dump");
+			return (-1);
+		}
+	}
+
+	/*
+	 * If zfs_swap or zfs_dump are specified, then name or mountpoint
+	 * shouldn't be.
+	 */
+	if (zfs_swap != Py_False || zfs_dump != Py_False) {
+		if (name != NULL || mountpoint != NULL) {
+			PyErr_SetString(PyExc_TypeError,
+			    "tgt.ZFSDataset() \"name\" and \"mountpoint\" are "
+			    "mutually exclusive with zfs_swap and zfs_dump");
+			return (-1);
+		}
+	}
+
+	if (name != NULL) {
+		self->name = strdup(name); /* can't be NULL */
+		if (self->name == NULL) {
+			PyErr_NoMemory();
+			return (-1);
+		}
+	}
+
+	if (mountpoint != NULL) {
+		self->mountpoint = strdup(mountpoint); /* can't be NULL */
+		if (self->mountpoint == NULL) {
+			PyErr_NoMemory();
+			return (-1);
+		}
+	}
+
+	if (be_name != NULL) {
+		self->be_name = strdup(be_name); /* can't be NULL */
+		if (self->be_name == NULL) {
+			PyErr_NoMemory();
+			return (-1);
+		}
+	}
+
+	self->zfs_swap = (zfs_swap == Py_True) ? 1 : 0;
+	self->zfs_dump = (zfs_dump == Py_True) ? 1 : 0;
+	self->swap_size = swap_size;
+	self->dump_size = dump_size;
+
+	return (0);
+}
+
+/*
+ * Function:    TgtZpool_Init
+ * Description: Initialize a tgt.Zpool object.
+ * Parameters:
+ *     self:    tgt.Zpool object to fill in
+ *     args:    the arguments given to Python to try to init object
+ *     kwds:    similar to args.
+ * Returns:     None
+ * Scope:       Private
+ *
+ */
+static int
+TgtZpool_Init(TgtZpool *self, PyObject *args, PyObject *kwds)
+{
+	int rc;
+	char *name = NULL;
+	char *device = NULL;
+
+	static char *kwlist[] = {
+		"name", "device", NULL
+	};
+
+	/*
+	 * Set default values for unrequired arguments.
+	 */
+	self->name = self->device = NULL;
+
+	rc = PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
+		&name, &device);
+
+	if (!rc)
+		return (-1);
+
+	self->name = strdup(name); /* can't be NULL */
+	if (self->name == NULL) {
+		PyErr_NoMemory();
+		return (-1);
+	}
+
+	self->device = strdup(device); /* can't be NULL */
+	if (self->device == NULL) {
+		PyErr_NoMemory();
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * Function:    TgtZpool_New
+ * Description: allocate and assign sensible initial values to a tgt.Zpool.
+ * Parameters:
+ *     type:    type object, do *NOT* assume it is TgtZpoolType!
+ *     args:    ignored, exists to match function prototype.
+ *     kwds:    ignored, exists to match function prototype.
+ * Returns:     None
+ * Scope:       Private
+ *
+ * NOTE: Unless you have not followed the MEMBER macros at the top there
+ *       is no reason to alter this function.
+ */
+/* ARGSUSED */
+static PyObject *
+TgtZpool_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+	TgtZpool *self = NULL;
+
+	self = (TgtZpool *)type->tp_alloc(type, 0);
+	if (self == NULL)
+		return (NULL); /* sets memory error */
+
+	if ((self->datasets = PyTuple_New(0)) == NULL) {
+		return (NULL);
+	}
+	self->name = self->device = NULL;
+
+	return ((PyObject *)self);
+}
+
+/*
+ * Function:    TgtZFSDataset_New
+ * Description: allocate and assign sensible initial values to a tgt.ZFSDataset.
+ * Parameters:
+ *     type:    type object, do *NOT* assume it is TgtDiskType!
+ *     args:    ignored, exists to match function prototype.
+ *     kwds:    ignored, exists to match function prototype.
+ * Returns:     None
+ * Scope:       Private
+ *
+ */
+/* ARGSUSED */
+static PyObject *
+TgtZFSDataset_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+	TgtZFSDataset *self = NULL;
+
+	self = (TgtZFSDataset *)type->tp_alloc(type, 0);
+	if (self == NULL)
+		return (NULL); /* sets memory error */
+
+	self->name = self->mountpoint = self->be_name = NULL;
+	self->zfs_swap = 0;
+	self->zfs_dump = 0;
+	self->swap_size = 0;
+	self->dump_size = 0;
+
+	return ((PyObject *)self);
+}
+
+
+/*
+ * Function:	TgtZpool_Deallocate
+ * Description:	Free up a TgtZpool
+ * Parameters:
+ * 	self:	TgtZpool to de-allocate
+ * Returns:	Nothing
+ * Scope:	Private
+ */
+static void
+TgtZpool_Deallocate(TgtZpool *self)
+{
+#define	FREE_STR(cname) \
+	if (self->cname != NULL) \
+		free(self->cname)
+	FREE_STR(name);
+	FREE_STR(device);
+#undef	FREE_STR
+
+	self->ob_type->tp_free((PyObject*)self);
+}
+
+/*
+ * Function:	TgtZFSDataset_Deallocate
+ * Description:	Free up a TgtZFSDataset
+ * Parameters:
+ * 	self:	TgtZFSDataset to de-allocate
+ * Returns:	Nothing
+ * Scope:	Private
+ */
+static void
+TgtZFSDataset_Deallocate(TgtZFSDataset *self)
+{
+#define	FREE_STR(cname) \
+	if (self->cname != NULL) \
+		free(self->cname)
+	FREE_STR(name);
+	FREE_STR(mountpoint);
+	FREE_STR(be_name);
+#undef	FREE_STR
+}
+
+PyDoc_STRVAR(TgtZpoolTypeDoc,
+"tgt.Zpool(name, device) -> tgt.Zpool object\n\
+\n\
+A Zpool object represents a zfs pool in the system.\n\
+\n");
+
+PyDoc_STRVAR(TgtZFSDatasetTypeDoc,
+"tgt.ZFSDataset(name, mountpoint, be_name, zfs_swap, swap_size, zfs_dump, \
+dump_size) -> tgt.ZFSDataset object\n\
+\n\
+A ZFSDataset object represents a zfs dataset in the system.\n\
+\n");
+
+static PyMemberDef TgtZpoolMembers[] = {
+	{
+		.name = "name",
+		.type = T_STRING,
+		.offset = offsetof(TgtZpool, name),
+		.doc = "zpool name"
+	}, {
+		.name = "device",
+		.type = T_STRING,
+		.offset = offsetof(TgtZpool, device),
+		.doc = "device for zpool"
+	}, {
+		.name = "datasets",
+		.type = T_OBJECT,
+		.offset = offsetof(TgtZpool, datasets),
+		.doc = "datasets in the zpool"
+	}, { NULL } /* Sentinel */
+};
+
+static PyMemberDef TgtZFSDatasetMembers[] = {
+	{
+		.name = "name",
+		.type = T_STRING,
+		.offset = offsetof(TgtZFSDataset, name),
+		.doc = "zfs dataset name"
+	}, {
+		.name = "mountpoint",
+		.type = T_STRING,
+		.offset = offsetof(TgtZFSDataset, mountpoint),
+		.doc = "zfs dataset mountpoint"
+	}, {
+		.name = "be_name",
+		.type = T_STRING,
+		.offset = offsetof(TgtZFSDataset, be_name),
+		.doc = "boot environment name"
+	}, {
+		.name = "zfs_swap",
+		.type = T_OBJECT,
+		.offset = offsetof(TgtZFSDataset, zfs_swap),
+		.doc = "Boolean to indicate whether to create a swap device"
+	}, {
+		.name = "swap_size",
+		.type = T_OBJECT,
+		.offset = offsetof(TgtZFSDataset, swap_size),
+		.doc = "size of zfs dataset to be used for swap"
+	}, {
+		.name = "zfs_dump",
+		.type = T_OBJECT,
+		.offset = offsetof(TgtZFSDataset, zfs_dump),
+		.doc = "Boolean to indicate whether to create a dump device"
+	}, {
+		.name = "dump_size",
+		.type = T_OBJECT,
+		.offset = offsetof(TgtZFSDataset, dump_size),
+		.doc = "size of zfs dataset to be used for dump"
+	}, { NULL } /* Sentinel */
+};
+
+PyTypeObject TgtZpoolType = {
+	PyObject_HEAD_INIT(NULL)
+	.ob_size = 0,
+	.tp_name = "tgt.Zpool",
+	.tp_basicsize = sizeof (TgtZpool),
+	.tp_dealloc = (destructor)TgtZpool_Deallocate,
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+	.tp_doc = TgtZpoolTypeDoc,
+	.tp_members = TgtZpoolMembers,
+	.tp_init = (initproc)TgtZpool_Init,
+	.tp_new = TgtZpool_New
+};
+
+PyTypeObject TgtZFSDatasetType = {
+	PyObject_HEAD_INIT(NULL)
+	.ob_size = 0,
+	.tp_name = "tgt.ZFSDataset",
+	.tp_basicsize = sizeof (TgtZFSDataset),
+	.tp_dealloc = (destructor)TgtZFSDataset_Deallocate,
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+	.tp_doc = TgtZFSDatasetTypeDoc,
+	.tp_members = TgtZFSDatasetMembers,
+	.tp_init = (initproc)TgtZFSDataset_Init,
+	.tp_new = TgtZFSDataset_New
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtarget_pymod/zpool.h	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,55 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_ZPOOL_H
+#define	_ZPOOL_H
+#include "Python.h"
+#include "structmember.h"
+
+/* We just need some constants, but it fails unless _FILE_OFFSET_BITS=32 */
+#undef	_FILE_OFFSET_BITS
+#define	_FILE_OFFSET_BITS	32
+
+typedef struct {
+	PyObject_HEAD
+	char	*name;			/* zfs dataset name */
+	char	*mountpoint;		/* zfs dataset mountpoint */
+	char	*be_name;		/* be name */
+	uint8_t	zfs_swap;		/* create a swap device */
+	uint32_t swap_size;		/* size of swap */
+	uint8_t zfs_dump;		/* create a dump device */
+	uint32_t dump_size;		/* size of dump */
+
+} TgtZFSDataset;
+
+typedef struct {
+	PyObject_HEAD
+	char *name;			/* zpool name (required) */
+	char *device;			/* device (required) */
+	PyObject *datasets;		/* zfs datasets */
+} TgtZpool;
+
+#endif	/* _ZPOOL_H */
--- a/usr/src/lib/libtd/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libtd/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # Target Discovery software library makefile
@@ -76,7 +76,7 @@
 	$(LINK.c) -o tdmgtst tdmgtst.o \
 		-R$(ROOTADMINLIB:$(ROOT)%=%) \
 		-L$(ROOTADMINLIB) -Lpics/$(ARCH) \
-		-ltd -llogsvc -lnvpair
+		-ltd -lfstyp -llogsvc -lnvpair
 
 # statically built Target Discovery Manager test program
 tdmgtst_static:	static tdmgtst.o
@@ -93,7 +93,7 @@
 	$(LINK.c) -o test_td test_td.o \
 		-R$(ROOTADMINLIB:$(ROOT)%=%) \
 		-L$(ROOTADMINLIB) -Lpics/$(ARCH) \
-		-ltd -llogsvc -lnvpair
+		-ltd -lfstyp -llogsvc -lnvpair
 
 # statically built Target Discovery test program
 test_td_static:	static test_td.o
--- a/usr/src/lib/libtd/td_api.h	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libtd/td_api.h	Tue Mar 16 14:07:17 2010 -0700
@@ -176,14 +176,23 @@
 #define	TD_SLICE_ATTR_TAG	"ddm_slice_tag"
 #define	TD_SLICE_ATTR_FLAG	"ddm_slice_flag"
 #define	TD_SLICE_ATTR_INUSE	"ddm_slice_inuse"
+#define	TD_SLICE_ATTR_USEDBY	"ddm_slice_usedby"
 #define	TD_SLICE_ATTR_MD_NAME	"ddm_slice_md_name"
 #define	TD_SLICE_ATTR_MD_COMPS	"ddm_slice_md_comps"
 #define	TD_SLICE_ATTR_DEVID	"ddm_slice_devid"
 
-typedef enum {
-	TD_SLICE_INUSE_NONE	= 0x00,
-	TD_SLICE_INUSE_SVM	= 0x01
-} td_slice_inuse_t;
+/* nv inuse types for slices */
+#define	TD_SLICE_USEDBY_MOUNT	"mount"
+#define	TD_SLICE_USEDBY_SVM	"svm"
+#define	TD_SLICE_USEDBY_LU	"lu"
+#define	TD_SLICE_USEDBY_DUMP	"dump"
+#define	TD_SLICE_USEDBY_VXVM	"vxvm"
+#define	TD_SLICE_USEDBY_FS	"fs"
+#define	TD_SLICE_USEDBY_VSFTAB	"vfstab"
+#define	TD_SLICE_USEDBY_EXPORT_ZPOOL	"exported_zpool"
+#define	TD_SLICE_USEDBY_ACTIVE_ZPOOL	"active_zpool"
+#define	TD_SLICE_USEDBY_SPARE_ZPOOL	"spare_zpool"
+#define	TD_SLICE_USEDBY_CACHE_ZPOOL	"l2cache_zpool"
 
 /* nv attribute names for Solaris instances */
 #define	TD_OS_ATTR_SLICE_NAME		"os_slice_name"
--- a/usr/src/lib/libtd/td_dd.c	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libtd/td_dd.c	Tue Mar 16 14:07:17 2010 -0700
@@ -50,9 +50,6 @@
 #include <td_dd.h>
 #include <ls_api.h>
 
-/* global variables */
-
-int ddm_inuse_svm_enabled = 0;
 
 /* local constants */
 
@@ -110,6 +107,23 @@
 	{ NULL, 		NULL }
 };
 
+/* nvlist namespace conversion table for slice inuse data */
+
+static char *ddm_slice_inuse_conv_tbl[][2] = {
+	{ DM_USE_MOUNT,		TD_SLICE_USEDBY_MOUNT },
+	{ DM_USE_SVM,		TD_SLICE_USEDBY_SVM },
+	{ DM_USE_LU,		TD_SLICE_USEDBY_LU },
+	{ DM_USE_DUMP,		TD_SLICE_USEDBY_DUMP },
+	{ DM_USE_VXVM,		TD_SLICE_USEDBY_VXVM },
+	{ DM_USE_FS,		TD_SLICE_USEDBY_FS },
+	{ DM_USE_VFSTAB,	TD_SLICE_USEDBY_VSFTAB },
+	{ DM_USE_EXPORTED_ZPOOL,	TD_SLICE_USEDBY_EXPORT_ZPOOL },
+	{ DM_USE_ACTIVE_ZPOOL,	TD_SLICE_USEDBY_ACTIVE_ZPOOL },
+	{ DM_USE_SPARE_ZPOOL,	TD_SLICE_USEDBY_SPARE_ZPOOL },
+	{ DM_USE_L2CACHE_ZPOOL,	TD_SLICE_USEDBY_CACHE_ZPOOL },
+	{ NULL, 		NULL }
+};
+
 /* private variables */
 
 /*
@@ -580,6 +594,7 @@
 	struct fs		*fsp = (struct fs *)sblock;
 	char			devpath[MAXPATHLEN];
 	int			fd;
+	static char		slasha[] = "/a/";
 
 	(void) snprintf(devpath, sizeof (devpath), "/dev/rdsk/%s",
 	    basename(slice_name));
@@ -607,6 +622,11 @@
 	    (strlen(fsp->fs_fsmnt) > (size_t)(MAXMNTLEN - 1)))
 		return (NULL);
 
+	/* if leading /a, strip it */
+	if (strncmp(fsp->fs_fsmnt, slasha, strlen(slasha)) == 0) {
+	    return (fsp->fs_fsmnt + 2);
+	}
+
 	return (fsp->fs_fsmnt);
 }
 
@@ -2074,12 +2094,131 @@
 		nvlist_add_string(nv_dst, TD_SLICE_ATTR_LASTMNT, last_mount);
 	}
 
+	/*
+	 * Get the inuse data and add it to the attribute list.
+	 */
+	if ((errn = ddm_get_slice_inuse_stats(name, nv_dst)) != 0) {
+		DDM_DEBUG(DDM_DBGLVL_ERROR,
+		    "ddm_get_slice_attributes(): Can't get slice inuse "
+		    "stats for %s, err=%d\n", name, errn);
+	}
+
 	/* slice name is not necessary anymore - free it */
 	dm_free_name(name);
 	return (nv_dst);
 }
 
 /*
+ * ddm_get_slice_inuse_stats()
+ * 	Get inuse data from libdiskmgt for a particular slice
+ * 	and add to passed in nv attribute list
+ * Parameters:	name	name of slice
+ *		nv_dst  nv attribute list to which inuse data is added
+ *
+ * Return:	0  - finished successfully
+ *	        error code - failed
+ */
+int
+ddm_get_slice_inuse_stats(char *name, nvlist_t *nv_dst)
+{
+	char *by, *data;
+	int errn;
+	int i;
+	nvlist_t *slice_stats;
+	nvpair_t *used_by = NULL;
+	nvpair_t *used_name = NULL;
+	char *name_src = NULL;
+	char *name_dst;
+
+	DDM_DEBUG(DDM_DBGLVL_NOTICE,
+	    "ddm_get_slice_inuse_stats(): name=%s\n", name);
+
+	dm_get_slice_stats(name, &slice_stats, &errn);
+
+	if (errn != 0) {
+	    DDM_DEBUG(DDM_DBGLVL_ERROR,
+		"ddm_get_slice_stats(): Can't get slice inuse data, "
+		"for %s, err=%d\n", name, errn);
+	    return (errn);
+	}
+
+	/*
+	 * While it is possible for there to be multiple pairs with the
+	 * key DM_USED_BY, such as when the slice is in use for a filesystem,
+	 * we are only interested in one, so will take the first one from the
+	 * nvlist.
+	 */
+	used_by = nvlist_next_nvpair(slice_stats, NULL);
+	used_name = nvlist_next_nvpair(slice_stats, used_by);
+
+	/*
+	 * No inuse data available
+	 */
+	if (used_by == NULL || used_name == NULL) {
+	    DDM_DEBUG(DDM_DBGLVL_NOTICE, "ddm_get_slice_inuse_stats(): "
+		"No inuse data available for %s\n", name);
+	    nvlist_free(slice_stats);
+	    return (0);
+	}
+
+	/*
+	 * Ensure data as expected
+	 */
+	if ((strcmp(nvpair_name(used_by), DM_USED_BY) != 0) ||
+	    (strcmp(nvpair_name(used_name), DM_USED_NAME) != 0)) {
+	    DDM_DEBUG(DDM_DBGLVL_ERROR, "ddm_get_slice_inuse_stats(): "
+		"Problem with inuse data for %s\n", name);
+	    nvlist_free(slice_stats);
+	    return (1);
+	}
+
+	/*
+	 * Get the inuse data strings
+	 */
+	nvpair_value_string(used_by, &by);
+	nvpair_value_string(used_name, &data);
+
+	if (by == NULL || data == NULL) {
+	    DDM_DEBUG(DDM_DBGLVL_ERROR, "ddm_get_slice_inuse_stats(): "
+		"NULL value for inuse data for %s\n", name);
+	    nvlist_free(slice_stats);
+	    return (1);
+	}
+
+	DDM_DEBUG(DDM_DBGLVL_NOTICE,
+	    "ddm_get_slice_inuse_stats(): used by=%s, data=%s\n",
+	    by, data);
+
+	/*
+	 * Convert the used_by values to those defined in libtd and add
+	 * the inuse data to the attribute list.
+	 */
+	for (i = 0; ddm_slice_inuse_conv_tbl[i][0] != NULL; i++) {
+	    if (strcmp(by, ddm_slice_inuse_conv_tbl[i][0]) == 0) {
+		name_src = ddm_slice_inuse_conv_tbl[i][0];
+		name_dst = ddm_slice_inuse_conv_tbl[i][1];
+		break;
+	    }
+	}
+
+	if (name_src == NULL) {
+	    DDM_DEBUG(DDM_DBGLVL_ERROR,
+		"ddm_get_slice_inuse_stats(): %s not in table\n", by);
+	    nvlist_free(slice_stats);
+	    return (1);
+	}
+
+	DDM_DEBUG(DDM_DBGLVL_NOTICE,
+	    "ddm_get_slice_inuse_stats(): name_dst=%s \n", name_dst);
+
+	nvlist_add_string(nv_dst, TD_SLICE_ATTR_USEDBY, name_dst);
+	nvlist_add_string(nv_dst, TD_SLICE_ATTR_INUSE, data);
+
+	nvlist_free(slice_stats);
+	return (0);
+}
+
+/*
  * ddm_free_handle_list()
  * Frees list of handles returned by
  * ddm_get_<object>() functions.
--- a/usr/src/lib/libtd/td_dd.h	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libtd/td_dd.h	Tue Mar 16 14:07:17 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -78,8 +78,6 @@
 
 #define	ddm_is_pathname(x)	((x) != NULL && *(x) == '/')
 
-/* global variables */
-extern int ddm_inuse_svm_enabled;
 
 /* function prototypes */
 extern ddm_handle_t	*ddm_get_disks(void);
@@ -90,6 +88,7 @@
 extern nvlist_t		*ddm_get_slice_attributes(ddm_handle_t s);
 extern void		ddm_free_handle_list(ddm_handle_t *h);
 extern void		ddm_free_attr_list(nvlist_t *attrs);
+extern int		ddm_get_slice_inuse_stats(char *, nvlist_t *);
 
 extern ddm_err_t
     ddm_slice_inuse_by_svm(char *slice, nvlist_t *attr, int *errp);
--- a/usr/src/lib/libtd/test_td.c	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libtd/test_td.c	Tue Mar 16 14:07:17 2010 -0700
@@ -169,15 +169,20 @@
 	" num |       name|           last mountpoint|\n"
 	"---------------------------------------------\n",
 
-	"-----------------------------------------------------------------\n"
-	" num |       name| idx| flg| tag| 1st block|#of blocks|size [MB]|\n"
-	"-----------------------------------------------------------------\n"
+	"-----------------------------------------------------------------"
+	"--------------------------\n"
+	" num |       name| idx| flg| tag| 1st block|#of blocks|size [MB]|"
+	"      inuse by|      inuse|\n"
+
+	"-----------------------------------------------------------------"
+	"--------------------------\n"
 },
 
 /* footer */
 {
 	"---------------------------------------------\n",
-	"-----------------------------------------------------------------\n"
+	"-----------------------------------------------------------------"
+	"--------------------------\n"
 },
 
 /* slice w/o attributes */
@@ -186,7 +191,9 @@
 	"         - |                        - |\n",
 
 /*	"       name| idx| flg| tag| 1st block|#of blocks|size [MB]|  " */
-	"         - |  - |  - |  - |        - |        - |       - |\n"
+	"         - |  - |  - |  - |        - |        - |       - |"
+/*	"      inuse by|      inuse|  " */
+        "            - |         - |\n"
 }
 };
 
@@ -659,6 +666,8 @@
 	uint64_t	start = 0;
 	uint64_t	size = 0;
 	uint32_t	ui32;
+	char		*inuse;
+	char		*usedby;
 	char		*name;
 	int		errp;
 
@@ -721,6 +730,18 @@
 		(void) printf("%9s|", "- ");
 	}
 
+	if (nvlist_lookup_string(attrs, TD_SLICE_ATTR_USEDBY, &usedby) == 0) {
+		(void) printf("%14s|", usedby);
+	} else {
+		(void) printf("%14s|", "- ");
+	}
+
+	if (nvlist_lookup_string(attrs, TD_SLICE_ATTR_INUSE, &inuse) == 0) {
+		(void) printf("%11s|", inuse);
+	} else {
+		(void) printf("%11s|", "- ");
+	}
+
 	(void) printf("\n");
 
 	/* device ID */
--- a/usr/src/lib/libti/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libti/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # Target Instantiation software library makefile
@@ -52,11 +52,11 @@
 		   -I$(ROOTINCADMIN)
 
 CPPFLAGS	+= $(INCLUDE) -D$(ARCH)
-CFLAGS		+= $(DEBUG_CFLAGS) -Xa $(CPPFLAGS)
+CFLAGS		+= -mt $(DEBUG_CFLAGS) -Xa $(CPPFLAGS)
 LDFLAGS		+=
 SOFLAGS		+= -L$(ROOTADMINLIB) -R$(ROOTADMINLIB:$(ROOT)%=%) \
 		-L$(ROOTUSRLIB) -R$(ROOTUSRLIB:$(ROOT)%=%) \
-		-ladm -lnvpair -llogsvc -lbe
+		-ladm -lnvpair -llogsvc -lbe -lefi
 
 ROOT_TEST_PROGS	= $(TEST_PROGS:%=$(ROOTOPTINSTALLTESTBIN)/%)
 CLEANFILES	= $(TEST_PROGS)
@@ -81,7 +81,7 @@
 		-lti -lbe -llogsvc \
 		-Bdynamic \
 		-ladm -lnvpair -lgen -lzfs -lpython2.6 -luuid \
-		-linstzones -lzonecfg -lcontract
+		-linstzones -lzonecfg -lcontract -lefi
 
 static: $(LIBS)
 
--- a/usr/src/lib/libti/ti_api.h	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libti/ti_api.h	Tue Mar 16 14:07:17 2010 -0700
@@ -19,12 +19,12 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#ifndef _TD_API_H
-#define	_TD_API_H
+#ifndef _TI_API_H
+#define	_TI_API_H
 
 /*
  * This header file is for users of the Target Instantiation library
@@ -64,7 +64,9 @@
 	TI_E_MKDIR_FAILED,		/* */
 	TI_E_MOUNT_FAILED,		/* */
 	TI_E_RMDIR_FAILED,		/* */
-	TI_E_PY_INVALID_ARG		/* invalid arg in Python interface */
+	TI_E_PY_INVALID_ARG,		/* invalid arg in Python interface */
+	TI_E_PY_NO_SPACE,		/* no spare error in Python interface */
+	TI_E_PY_SWAP_INVALID		/* swap choice may cause install failure */
 } ti_errno_t;
 
 /* type of callback function reporting progress */
@@ -320,4 +322,4 @@
 }
 #endif
 
-#endif /* _TD_API_H */
+#endif /* _TI_API_H */
--- a/usr/src/lib/libti/ti_dm.c	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libti/ti_dm.c	Tue Mar 16 14:07:17 2010 -0700
@@ -38,6 +38,7 @@
 #include <sys/swap.h>
 #include <sys/types.h>
 #include <sys/vtoc.h>
+#include <sys/efi_partition.h>
 #include <errno.h>
 
 #include <ti_dm.h>
@@ -1501,12 +1502,24 @@
 
 	if (ioctl(fd, DKIOCGGEOM, &geom) == -1) {
 		if (errno == ENOTSUP) {
+			/*
+			 * DKIOCGGEOM is not supported on EFI/GPT disks.
+			 * Use efi_alloc_and_read to verify we have EFI/GPT.
+			 */
+			struct dk_gpt	*efip;
+			if (efi_alloc_and_read(fd, &efip) >= 0) {
 
-		    /* EFI label */
+				/* EFI label */
 
-			idm_debug_print(LS_DBGLVL_INFO, "Disk %s has "
-			    "an EFI label\n", disk_name);
-			EFI = B_TRUE;
+				idm_debug_print(LS_DBGLVL_INFO, "Disk %s has "
+				    "an EFI label\n", disk_name);
+				EFI = B_TRUE;
+				efi_free(efip);
+			} else {
+				idm_debug_print(LS_DBGLVL_INFO, "Disk %s "
+				    "returns ENOTSUP but does not have an "
+				    "EFI label\n", disk_name);
+			}
 
 		} else {
 
--- a/usr/src/lib/libtransfer/transfer_mod.py	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/lib/libtransfer/transfer_mod.py	Tue Mar 16 14:07:17 2010 -0700
@@ -412,7 +412,10 @@
 
         # Get the optimized libc overlay out of the way.
         # Errors from umount intentionally ignored
-        os.system("umount /lib/libc.so.1")
+        null_handle = open("/dev/null", "w")
+        sp.Popen(["/usr/sbin/umount", "/lib/libc.so.1"], stdout=null_handle,
+                 stderr=null_handle)
+        null_handle.close()
 
         self.info_msg("Building cpio file lists")
 
@@ -869,7 +872,7 @@
             raise TAbort("Invalid CPIO action",
                          TM_E_INVALID_CPIO_ACT_ATTR)
 
-        tmod.logprogress(100, "Complete transfer process")
+        tmod.logprogress(100, "Completing transfer process")
         self.info_msg("-- Completed transfer process, " +
                       time.strftime(self.tformat) + " --")
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libzoneinfo_pymod/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,59 @@
+#
+# 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 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 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY		= libzoneinfo
+
+OBJECTS		= libzoneinfo.o
+
+CPYTHONLIBS	= libzoneinfo.so
+
+PRIVHDRS	=
+EXPHDRS		=
+HDRS		= $(EXPHDRS) $(PRIVHDRS)
+
+include ../Makefile.lib
+
+INCLUDE		= -I/usr/include/python2.6 -I/usr/include/libzoneinfo
+
+CPPFLAGS	+= ${INCLUDE} $(CPPFLAGS.master) -D_FILE_OFFSET_BITS=64
+CFLAGS		+= $(DEBUG_CFLAGS) -Xa ${CPPFLAGS} 
+SOFLAGS		+= -L$(ROOTADMINLIB) -R$(ROOTADMINLIB:$(ROOT)%=%) \
+		-lzoneinfo -lpython2.6
+
+static:	
+
+dynamic:	$(CPYTHONLIB)
+
+all:		$(HDRS) dynamic
+
+install_h:
+
+install:	all .WAIT \
+		$(ROOTPYTHONVENDOR) \
+		$(ROOTPYTHONVENDORINSTALL) \
+		$(ROOTPYTHONVENDORINSTALLLIBS) 
+
+lint:		lint_SRCS
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libzoneinfo_pymod/libzoneinfo.c	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,312 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <Python.h>
+#include <libzoneinfo.h>
+#include <locale.h>
+
+static PyObject *get_tz_info(PyObject *self, PyObject *args);
+static PyObject *tz_isvalid(PyObject *self, PyObject *args);
+
+/*
+ * Create the method table that translates the method called
+ * by the python program to the associated c function
+ */
+static PyMethodDef libzoneinfoMethods[] = {
+	{"get_tz_info", (PyCFunction)get_tz_info, METH_VARARGS,
+	"Get timezone information from libzoneinfo"},
+	{"tz_isvalid", (PyCFunction)tz_isvalid, METH_VARARGS,
+	"Check if timezone is valid per libzoneinfo"},
+	{NULL, NULL, 0, NULL} };
+
+
+PyMODINIT_FUNC
+initlibzoneinfo(void)
+{
+	(void) Py_InitModule("libzoneinfo", libzoneinfoMethods);
+}
+
+/*
+ * get_tz_info
+ *
+ * Description: Calls:
+ *                  libzoneinfo:get_tz_continents,
+ *                  libzoneinfo:get_tz_countries, and
+ *                  libzoneinfo:get_timezones_by_country
+ *              to obtain timezone information.
+ * Parameters:
+ *   arguments - pointer to a python object containing 0, 1, or 2 args.
+ *               Number of args determines type of information returned
+ *                   0 args - returns continent info
+ *                   1 arg (ctnt_name) - returns country info
+ *                   2 args (ctnt_name, ctry_code) - returns timezone info
+ * Returns:
+ *      On success: pylist of tuples, each tuple has three elements:
+ *		tz_name: names of continent, country, or timezone
+ *		tz_descr: descriptive name of continent, country,
+ *                        or timezone
+ *		tz_loc: localized name of continent, country,
+ *                        or timezone
+ *      On failure: empty pylist (or memory error if unable to create pylist)
+ */
+static PyObject *
+get_tz_info(PyObject *self, PyObject *args)
+{
+	char *cont_name = NULL;
+	char *cntry_name = NULL;
+	struct	tz_continent *ctnts = NULL;
+	struct tz_continent *pctnt = NULL;
+	int nctnt;
+	int i = 0;
+
+	PyObject	*tz_tuple = NULL;
+	PyObject	*tz_tuple_list = NULL;
+	PyObject	*empty_list = NULL;
+
+	if ((tz_tuple_list = PyList_New(0)) == NULL) {
+	    return (PyErr_NoMemory());
+	}
+
+	if ((empty_list = PyList_New(0)) == NULL) {
+	    return (PyErr_NoMemory());
+	}
+
+	/*
+	 * Can be called with 0, 1, or 2 args
+	 *   0 args - returns continent info
+	 *   1 arg (ctnt_name) - returns country info
+	 *   2 args (ctnt_name, ctry_code) - returns timezone info
+	 */
+	if (!PyArg_ParseTuple(args, "|zz", &cont_name, &cntry_name)) {
+		return (Py_BuildValue("O", empty_list));
+	}
+
+	/*
+	 * Pickup locale
+	 */
+	setlocale(LC_MESSAGES, "");
+
+	/*
+	 * Make library call
+	 */
+	nctnt = get_tz_continents(&ctnts);
+	if (nctnt == -1) {
+		return (Py_BuildValue("O", empty_list));
+	}
+
+	for (i = 1, pctnt = ctnts; pctnt != NULL;
+			pctnt = pctnt->ctnt_next, i++) {
+		PyObject *item_name = NULL;
+		PyObject *item_desc = NULL;
+		PyObject *item_loc = NULL;
+		char *curcont = NULL;
+		int nctry;
+		int j;
+		struct tz_country *cntries;
+		struct tz_country *pctry;
+
+		if (cont_name == NULL) {
+			/*
+			 * Create list of continent tuples, each with:
+			 *	continent name
+			 *	continent name descriptive
+			 *	localized continent name
+			 */
+			if ((tz_tuple = PyTuple_New(3)) == NULL) {
+				return (Py_BuildValue("O", empty_list));
+			}
+
+			/*
+			 * Need to get continent list
+			 */
+			item_name = PyString_FromString(pctnt->ctnt_name);
+			if (pctnt->ctnt_id_desc != NULL) {
+				item_desc = PyString_FromString(
+				    pctnt->ctnt_id_desc);
+			} else {
+				item_desc = PyString_FromString("");
+			}
+
+			if (pctnt->ctnt_display_desc != NULL) {
+				item_loc = PyString_FromString(
+				    pctnt->ctnt_display_desc);
+			} else {
+				item_loc = PyString_FromString("");
+			}
+
+			PyTuple_SetItem(tz_tuple, 0, item_name);
+			PyTuple_SetItem(tz_tuple, 1, item_desc);
+			PyTuple_SetItem(tz_tuple, 2, item_loc);
+			if (PyList_Append(tz_tuple_list, tz_tuple) != 0) {
+				return (Py_BuildValue("O", empty_list));
+			}
+			Py_DECREF(tz_tuple);
+			continue;
+		}
+
+		/*
+		 * Name of continent passed in. Look for match.
+		 */
+		curcont = pctnt->ctnt_name;
+		if (strncmp(curcont, cont_name, strlen(cont_name)) != 0) {
+			continue;
+		}
+
+		/*
+		 * Found matching continent. Now get its countries.
+		 */
+		nctry = get_tz_countries(&cntries, pctnt);
+		if (nctry == -1) {
+			return (Py_BuildValue("O", empty_list));
+		}
+		for (j = 1, pctry = cntries; pctry != NULL;
+				pctry = pctry->ctry_next, j++) {
+			struct tz_timezone *tzs;
+			struct tz_timezone *ptz;
+			char *cur_country = NULL;
+			int ntz;
+			int k;
+
+			/*
+			 * Create list of country tuples, each with:
+			 *	country name/id
+			 *	country name descriptive
+			 *	localized country name
+			 */
+			if (cntry_name == NULL) {
+				if ((tz_tuple = PyTuple_New(3)) == NULL) {
+					return (Py_BuildValue("O", empty_list));
+				}
+				item_name = PyString_FromString(
+				    pctry->ctry_code);
+				if (pctry->ctry_id_desc != NULL) {
+					item_desc = PyString_FromString(
+					    pctry->ctry_id_desc);
+				} else {
+					item_desc = PyString_FromString("");
+				}
+				if (pctry->ctry_display_desc != NULL) {
+					item_loc = PyString_FromString(
+					    pctry->ctry_display_desc);
+				} else {
+					item_loc = PyString_FromString("");
+				}
+
+				PyTuple_SetItem(tz_tuple, 0, item_name);
+				PyTuple_SetItem(tz_tuple, 1, item_desc);
+				PyTuple_SetItem(tz_tuple, 2, item_loc);
+				if (PyList_Append(tz_tuple_list,
+				    tz_tuple) != 0) {
+					return (Py_BuildValue("O", empty_list));
+				}
+				Py_DECREF(tz_tuple);
+				continue;
+			}
+
+			/*
+			 * Name of country passed in. Look for match.
+			 */
+			cur_country = pctry->ctry_code;
+			if (strncmp(cur_country, cntry_name,
+			    strlen(cntry_name)) != 0) {
+				continue;
+			}
+
+			/*
+			 *  Found matching country. Now get its timezones.
+			 */
+			ntz = get_timezones_by_country(&tzs, pctry);
+
+			for (k = 1, ptz = tzs; ptz != NULL;
+			    ptz = ptz->tz_next) {
+				/*
+				 * Create list of timezone tuples, each with:
+				 *	timezone name
+				 *	timezone name descriptive
+				 *	localized timezone name
+				 *	tz_loc: localized timezone names
+				 */
+				if ((tz_tuple = PyTuple_New(3)) == NULL) {
+					return (Py_BuildValue("O", empty_list));
+				}
+				item_name = PyString_FromString(ptz->tz_name);
+				if (ptz->tz_id_desc != NULL) {
+					item_desc = PyString_FromString(
+					    ptz->tz_id_desc);
+				} else {
+					item_desc = PyString_FromString("");
+				}
+				if (ptz->tz_display_desc != NULL) {
+					item_loc = PyString_FromString(
+					    ptz->tz_display_desc);
+				} else {
+					item_loc = PyString_FromString("");
+				}
+
+				PyTuple_SetItem(tz_tuple, 0, item_name);
+				PyTuple_SetItem(tz_tuple, 1, item_desc);
+				PyTuple_SetItem(tz_tuple, 2, item_loc);
+				if (PyList_Append(tz_tuple_list,
+				    tz_tuple) != 0) {
+					return (Py_BuildValue("O", empty_list));
+				}
+				Py_DECREF(tz_tuple);
+			}
+			(void) free_timezones(tzs);
+			break;
+		}
+		(void) free_tz_countries(cntries);
+		break;
+	}
+
+	(void) free_tz_continents(ctnts);
+	return (Py_BuildValue("O", tz_tuple_list));
+}
+
+
+/*
+ * tz_isvalid
+ *
+ * Description: Calls:
+ *                  libzoneinfo:isvalid_tz
+ *              to check if timezone is valid.
+ * Parameters:
+ *   arguments - pointer to a python object containing name of timezone
+ *		 to be checked for validity
+ * Returns:
+ *      1, if timezone is valid per libzoneinfo:isvalid_tz
+ */
+static PyObject *
+tz_isvalid(PyObject *self, PyObject *args)
+{
+	char *timezone = NULL;
+
+	if (!PyArg_ParseTuple(args, "s", &timezone)) {
+		return (Py_BuildValue("i", 2));
+	}
+
+	return (Py_BuildValue("i", isvalid_tz(timezone, "/", _VTZ_ZONEINFO)));
+}
--- a/usr/src/pkgdefs/Makefile	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/pkgdefs/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -42,8 +42,8 @@
 	SUNWinstall-libs \
 	SUNWinstall-test \
 	SUNWinstalladm-tools \
-	SUNWslim-utils
-
+	SUNWslim-utils \
+	SUNWtext-install
 
 SUBDIRS		= $(COMMON_SUBDIRS)
 
--- a/usr/src/pkgdefs/SUNWdistro-const/prototype_com	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/pkgdefs/SUNWdistro-const/prototype_com	Tue Mar 16 14:07:17 2010 -0700
@@ -86,12 +86,11 @@
 d none usr/share/distro_const 0755 root bin
 d none usr/share/distro_const/auto_install 0755 root bin
 d none usr/share/distro_const/slim_cd 0755 root bin
+d none usr/share/distro_const/text_install 0755 root bin
 d none usr/share/distro_const/vmc 0755 root bin
 f none usr/share/distro_const/auto_install/ai_boot_archive_configure 0555 root bin
 f none usr/share/distro_const/auto_install/ai_live.xml 0444 root sys
-f none usr/share/distro_const/auto_install/ai_post_boot_archive_pkg_image_mod 0555 root bin
 f none usr/share/distro_const/auto_install/ai_pre_boot_archive_pkg_image_mod 0555 root bin
-f none usr/share/distro_const/auto_install/ai_plat_setup.py 0555 root bin
 f none usr/share/distro_const/auto_install/ai_sparc_image.xml 0444 root sys
 f none usr/share/distro_const/auto_install/ai_x86_image.xml 0444 root sys
 f none usr/share/distro_const/boot_archive_archive.py 0555 root bin
@@ -106,19 +105,26 @@
 f none usr/share/distro_const/DC-manifest.rng 0444 root sys
 f none usr/share/distro_const/finalizer_checkpoint.py 0555 root bin
 f none usr/share/distro_const/finalizer_rollback.py 0555 root bin
+f none usr/share/distro_const/gen_cd_content 0555 root bin
 f none usr/share/distro_const/grub_setup.py 0555 root bin
 f none usr/share/distro_const/mkrepo 0555 root bin
+f none usr/share/distro_const/plat_setup.py 0555 root bin
 f none usr/share/distro_const/post_boot_archive_pkg_image_mod 0555 root bin
+f none usr/share/distro_const/post_boot_archive_pkg_image_mod_custom 0555 root bin
 f none usr/share/distro_const/pre_boot_archive_pkg_image_mod.py 0555 root bin
 f none usr/share/distro_const/generic_live.xml 0444 root sys
 f none usr/share/distro_const/slim_cd/all_lang_slim_cd_x86.xml 0444 root sys
 f none usr/share/distro_const/slim_cd/slimcd_boot_archive_configure 0555 root bin
-f none usr/share/distro_const/slim_cd/slimcd_gen_cd_content 0555 root bin
 f none usr/share/distro_const/slim_cd/slimcd_live.xml 0444 root sys
 f none usr/share/distro_const/slim_cd/slimcd_iso.sort 0444 root sys
 f none usr/share/distro_const/slim_cd/slimcd_post_boot_archive_pkg_image_mod 0555 root bin
 f none usr/share/distro_const/slim_cd/slimcd_pre_boot_archive_pkg_image_mod 0555 root bin
 f none usr/share/distro_const/slim_cd/slim_cd_x86.xml 0444 root sys
+f none usr/share/distro_const/text_install/text_install_x86_iso.sort 0444 root sys
+f none usr/share/distro_const/text_install/text_mode_x86.xml 0444 root sys
+f none usr/share/distro_const/text_install/text_mode_sparc.xml 0444 root sys
+f none usr/share/distro_const/text_install/text_live.xml 0444 root sys
+f none usr/share/distro_const/text_install/tm_pre_boot_archive_pkg_image_mod 0555 root bin
 f none usr/share/distro_const/vmc/create_vm 0555 root bin
 f none usr/share/distro_const/vmc/export_vm 0555 root bin
 s none usr/share/distro_const/vmc/export_esx=export_vm
--- a/usr/src/pkgdefs/SUNWinstall/prototype_com	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/pkgdefs/SUNWinstall/prototype_com	Tue Mar 16 14:07:17 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -74,12 +74,16 @@
 f none usr/lib/python2.6/vendor-packages/osol_install/liblogsvc.so 0755 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/libti.so 0755 root bin
 s none usr/lib/python2.6/vendor-packages/osol_install/libtransfer.so=../../../../snadm/lib/libtransfer.so
+f none usr/lib/python2.6/vendor-packages/osol_install/libzoneinfo.so 0755 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/ManifestRead.py 0644 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/ManifestRead.pyc 0644 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/ManifestServ.py 0644 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/ManifestServ.pyc 0644 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/SocketServProtocol.py 0644 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/SocketServProtocol.pyc 0644 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/tgt.so 0644 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/tgt_utils.py 0644 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/tgt_utils.pyc 0644 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/ti_defs.py 0644 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/ti_defs.pyc 0644 root bin
 f none usr/lib/python2.6/vendor-packages/osol_install/transfer_defs.py 0644 root bin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWtext-install/Makefile	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,38 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+
+DATAFILES +=
+
+MACHDATAFILES =
+
+.KEEP_STATE:
+
+all: $(FILES) $(MACHDATAFILES)
+install: all .WAIT pkg
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWtext-install/depend	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,46 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+#
+# This package information file defines software dependencies associated
+# with the pkg.  You can define three types of pkg dependencies with this file:
+#	 P indicates a prerequisite for installation
+#	 I indicates an incompatible package
+#	 R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# 	(<arch>)<version>
+# 	(<arch>)<version>
+# 	...
+# <type> <pkg.abbr> <name>
+# ...
+
+P SUNWinstall-libs	System install libraries
+P SUNWinstall	System install libraries and commands
+P SUNWPython26	The Python interpreter, libraries and utilities
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWtext-install/prototype_com	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,163 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#
+# source locations relative to the prototype file
+#
+# SUNWtext-install
+#
+i pkginfo
+i copyright
+i depend
+
+d none usr/bin 0755 root bin
+f none usr/bin/text-install 0555 root sys
+d none usr 0755 root sys
+d none usr/lib 0755 root bin
+d none usr/lib/python2.6 0755 root bin
+d none usr/lib/python2.6/vendor-packages 0755 root bin
+d none usr/lib/python2.6/vendor-packages/osol_install 0755 root bin
+d none usr/lib/python2.6/vendor-packages/osol_install/profile 0755 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/__init__.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/__init__.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/disk_info.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/disk_info.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/disk_space.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/disk_space.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/install_profile.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/install_profile.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/ip_address.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/ip_address.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/network_info.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/network_info.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/partition_info.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/partition_info.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/slice_info.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/slice_info.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/system_info.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/system_info.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/user_info.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/profile/user_info.pyc 0444 root bin
+d none usr/lib/python2.6/vendor-packages/osol_install/text_install 0755 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/__init__.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/__init__.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/action.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/action.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/base_screen.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/base_screen.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/color_theme.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/color_theme.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/date_time.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/date_time.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/disk_selection.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/disk_selection.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/disk_window.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/disk_window.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/edit_field.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/edit_field.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/error_window.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/error_window.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/fdisk_partitions.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/fdisk_partitions.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/help_screen.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/help_screen.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/inner_window.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/inner_window.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/install_progress.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/install_progress.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/install_status.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/install_status.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/list_item.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/list_item.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/log_viewer.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/log_viewer.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/main_window.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/main_window.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/network_nic_configure.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/network_nic_configure.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/network_nic_select.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/network_nic_select.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/network_type.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/network_type.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/partition_edit_screen.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/partition_edit_screen.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/screen_list.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/screen_list.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/scroll_window.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/scroll_window.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/summary.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/summary.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/ti_install.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/ti_install.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/ti_install_utils.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/ti_install_utils.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/timezone.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/timezone.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/users.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/users.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/welcome.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/welcome.pyc 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/window_area.py 0444 root bin
+f none usr/lib/python2.6/vendor-packages/osol_install/text_install/window_area.pyc 0444 root bin
+d none usr/share 0755 root sys
+d none usr/share/text-install 0755 root sys
+d none usr/share/text-install/help 0755 root sys
+d none usr/share/text-install/help/C 0755 root sys
+f none usr/share/text-install/help/C/date_time.txt=usr/share/text-install/date_time.txt 0644 root sys
+f none usr/share/text-install/help/C/disks.txt=usr/share/text-install/disks.txt 0644 root sys
+f none usr/share/text-install/help/C/network.txt=usr/share/text-install/network.txt 0644 root sys
+f none usr/share/text-install/help/C/network_manual.txt=usr/share/text-install/network_manual.txt 0644 root sys
+f none usr/share/text-install/help/C/sparc_solaris_slices.txt=usr/share/text-install/sparc_solaris_slices.txt 0644 root sys
+f none usr/share/text-install/help/C/sparc_solaris_slices_select.txt=usr/share/text-install/sparc_solaris_slices_select.txt 0644 root sys
+f none usr/share/text-install/help/C/summary.txt=usr/share/text-install/summary.txt 0644 root sys
+f none usr/share/text-install/help/C/timezone.txt=usr/share/text-install/timezone.txt 0644 root sys
+f none usr/share/text-install/help/C/users.txt=usr/share/text-install/users.txt 0644 root sys
+f none usr/share/text-install/help/C/welcome.txt=usr/share/text-install/welcome.txt 0644 root sys
+f none usr/share/text-install/help/C/x86_fdisk_partitions.txt=usr/share/text-install/x86_fdisk_partitions.txt 0644 root sys
+f none usr/share/text-install/help/C/x86_fdisk_partitions_select.txt=usr/share/text-install/x86_fdisk_partitions_select.txt 0644 root sys
+f none usr/share/text-install/help/C/x86_fdisk_slices.txt=usr/share/text-install/x86_fdisk_slices.txt 0644 root sys
+f none usr/share/text-install/help/C/x86_fdisk_slices_select.txt=usr/share/text-install/x86_fdisk_slices_select.txt 0644 root sys
+d none var 0755 root sys
+d none var/svc 0755 root sys
+d none var/svc/manifest 0755 root sys
+d none var/svc/manifest/system 0755 root sys
+f none var/svc/manifest/system/text-mode-menu.xml 0444 root sys
+d none usr/sbin 0755 root bin
+f none usr/sbin/text-mode-menu 0555 root bin
+
+#
+# Need to use ict_test to invoke C based ICT for now.  This should be
+# removed when bug 6256 is fixed.
+#
+d none opt 0755 root sys
+d none opt/install-test 0755 root sys
+d none opt/install-test/bin 0755 root bin
+f none opt/install-test/bin/ict_test 0555 root bin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWtext-install/prototype_i386	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,50 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>        # where to find pkg objects
+#!include <filename>                    # include another 'prototype' file
+#!default <mode> <owner> <group>        # default used if not specified on entry#!<param>=<value>                       # puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+#
+#
+# List files which are i386 specific here
+#
+# source locations relative to the prototype file
+#
+#
+# SUNWtext-install
+#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWtext-install/prototype_sparc	Tue Mar 16 14:07:17 2010 -0700
@@ -0,0 +1,51 @@
+#
+# 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 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>        # where to find pkg objects
+#!include <filename>                    # include another 'prototype' file
+#!default <mode> <owner> <group>        # default used if not specified on entry
+#!<param>=<value>                       # puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+#
+#
+# List files which are SPARC specific here
+#
+# source locations relative to the prototype file
+#
+#
+# SUNWtext-install
+#
--- a/usr/src/tools/env/install.pylintrc	Mon Mar 15 11:50:38 2010 -0600
+++ b/usr/src/tools/env/install.pylintrc	Tue Mar 16 14:07:17 2010 -0700
@@ -186,7 +186,7 @@
 
 # List of classes names for which member attributes should not be checked
 # (useful for classes with attributes dynamicaly set).
-ignored-classes=SQLObject
+ignored-classes=SQLObject,curses
 
 # When zope mode is activated, add a predefined set of Zope acquired attributes
 # to generated-members.