5821 Sparc AI microroot is not fully writable
authorJack Schwartz <Jack.A.Schwartz@Sun.COM>
Thu, 08 Jan 2009 17:06:12 -0800
changeset 401 2f6d4bf63451
parent 400 f7861b6d6614
child 402 97a45e564c5c
5821 Sparc AI microroot is not fully writable 5802 system calls to find should be investigated to see if an os.walk would be better
usr/src/cmd/distro_const/DC-manifest.rng
usr/src/cmd/distro_const/DC_defs.py
usr/src/cmd/distro_const/auto_install/ai_sparc_image.xml
usr/src/cmd/distro_const/utils/bootroot_archive.py
usr/src/lib/install_utils/install_utils.py
--- a/usr/src/cmd/distro_const/DC-manifest.rng	Thu Jan 08 13:23:22 2009 -0700
+++ b/usr/src/cmd/distro_const/DC-manifest.rng	Thu Jan 08 17:06:12 2009 -0800
@@ -18,7 +18,7 @@
 
 CDDL HEADER END
 
-Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 Use is subject to license terms.
 -->
 
@@ -338,14 +338,11 @@
 		<element name="bootroot_contents">
 			<interleave>
 				<oneOrMore>
-					<element name="base_include">
-						<ref name="nm_filetype_attr"/>
-						<text/>
-					</element>
+					<ref name="nm_base_include"/>
 				</oneOrMore>
 				<zeroOrMore>
 					<element name="base_exclude">
-						<ref name="nm_filetype_attr"/>
+						<ref name="nm_excltype_attr"/>
 						<text/>
 					</element>
 				</zeroOrMore>
@@ -356,15 +353,61 @@
 		</element>
 	</define>
 
-	<define name="nm_filetype_attr">
-		<optional>
+	<!--
+	Files to be included may be specified as individual files or as
+	directories of files.  On some platforms per-file compression is done by
+	default.  This can be disabled on individual files which are read in as
+	part of a directory of files, by base_include'ing that file and
+	specifying fiocompress="false" for it.
+	-->
+
+	<define name="nm_base_include">
+		<element name="base_include">
+			<choice>
+				<!-- Can be either files or dirs,
+					but files allow more attributes. -->
+				<ref name="nm_inclfiletype_attr"/>
+				<ref name="nm_incldirtype_attr"/>
+			</choice>
+			<text/>
+		</element>
+	</define>
+
+	<define name="nm_inclfiletype_attr">
+		<group>
+			<!-- In the case of "type = file", allow fiocompress -->
+			<attribute name="type">
+				<choice>
+					<value>file</value>
+				</choice>
+			</attribute>
+			<optional>
+				<attribute name="fiocompress">
+					<data type="boolean"/>
+				</attribute>
+			</optional>
+		</group>
+	</define>
+
+	<define name="nm_incldirtype_attr">
+		<group>
+			<attribute name="type">
+				<choice>
+					<value>dir</value>
+				</choice>
+			</attribute>
+		</group>
+	</define>
+
+	<define name="nm_excltype_attr">
+		<group>
 			<attribute name="type">
 				<choice>
 					<value>file</value>
 					<value>dir</value>
 				</choice>
 			</attribute>
-		</optional>
+		</group>
 	</define>
 
 	<!--
--- a/usr/src/cmd/distro_const/DC_defs.py	Thu Jan 08 13:23:22 2009 -0700
+++ b/usr/src/cmd/distro_const/DC_defs.py	Thu Jan 08 17:06:12 2009 -0800
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -67,10 +67,15 @@
 GENERATE_IPS_INDEX = IMG_PARAMS + "/generate_ips_search_index"
 BOOT_ROOT_CONTENTS = IMG_PARAMS + "/bootroot_contents"
 BOOT_ROOT_CONTENTS_BASE_INCLUDE = BOOT_ROOT_CONTENTS + "/base_include" 
+BOOT_ROOT_CONTENTS_BASE_INCLUDE_NOCOMPRESS = \
+    BOOT_ROOT_CONTENTS_BASE_INCLUDE + "[fiocompress=\"false\"]"
 BOOT_ROOT_CONTENTS_BASE_EXCLUDE = BOOT_ROOT_CONTENTS + "/base_exclude" 
-BOOT_ROOT_CONTENTS_BASE_INCLUDE_TO_TYPE_DIR = BOOT_ROOT_CONTENTS_BASE_INCLUDE + "[type=\"dir\"]"
-BOOT_ROOT_CONTENTS_BASE_EXCLUDE_TO_TYPE_DIR = BOOT_ROOT_CONTENTS_BASE_EXCLUDE + "[type=\"dir\"]"
-BOOT_ROOT_CONTENTS_BASE_INCLUDE_TO_TYPE_FILE = BOOT_ROOT_CONTENTS_BASE_INCLUDE + "[type=\"file\"]"
+BOOT_ROOT_CONTENTS_BASE_INCLUDE_TO_TYPE_DIR = \
+    BOOT_ROOT_CONTENTS_BASE_INCLUDE + "[type=\"dir\"]"
+BOOT_ROOT_CONTENTS_BASE_EXCLUDE_TO_TYPE_DIR = \
+    BOOT_ROOT_CONTENTS_BASE_EXCLUDE + "[type=\"dir\"]"
+BOOT_ROOT_CONTENTS_BASE_INCLUDE_TO_TYPE_FILE = \
+    BOOT_ROOT_CONTENTS_BASE_INCLUDE + "[type=\"file\"]"
 OUTPUT_IMAGE = IMG_PARAMS + "/output_image"
 OUTPUT_IMAGE_BOOTROOT = OUTPUT_IMAGE + "/bootroot"
 BOOT_ROOT_COMPRESSION_TYPE = OUTPUT_IMAGE_BOOTROOT + "/compression/type"
@@ -85,12 +90,16 @@
 FINALIZER_SCRIPT = OUTPUT_IMAGE + "/finalizer/script"
 FINALIZER_SCRIPT_NAME = FINALIZER_SCRIPT + "/name"
 FINALIZER_SCRIPT_ARGS = FINALIZER_SCRIPT + "/argslist"
-FINALIZER_SCRIPT_NAME_TO_CHECKPOINT_MESSAGE = FINALIZER_SCRIPT + "[name=\"%s\"]/checkpoint/message"
-FINALIZER_SCRIPT_NAME_TO_CHECKPOINT_NAME = FINALIZER_SCRIPT + "[name=\"%s\"]/checkpoint/name"
+FINALIZER_SCRIPT_NAME_TO_CHECKPOINT_MESSAGE = \
+    FINALIZER_SCRIPT + "[name=\"%s\"]/checkpoint/message"
+FINALIZER_SCRIPT_NAME_TO_CHECKPOINT_NAME = \
+    FINALIZER_SCRIPT + "[name=\"%s\"]/checkpoint/name"
 ADD_AUTH_URL_TO_AUTHNAME = ADD_AUTH_MAIN + "[url=\"%s\"]/authname"
 ADD_AUTH_URL_TO_MIRROR_URL = ADD_AUTH_MAIN + "[url=\"%s\"]/../mirror/url"
-POST_INSTALL_ADD_URL_TO_AUTHNAME = POST_INSTALL_ADD_AUTH_MAIN + "[url=\"%s\"]/authname"
-POST_INSTALL_ADD_URL_TO_MIRROR_URL = POST_INSTALL_ADD_AUTH_MAIN + "[url=\"%s\"]/../mirror/url"
+POST_INSTALL_ADD_URL_TO_AUTHNAME = \
+    POST_INSTALL_ADD_AUTH_MAIN + "[url=\"%s\"]/authname"
+POST_INSTALL_ADD_URL_TO_MIRROR_URL = \
+    POST_INSTALL_ADD_AUTH_MAIN + "[url=\"%s\"]/../mirror/url"
 FINALIZER_SCRIPT_NAME_TO_ARGSLIST = FINALIZER_SCRIPT + "[name=\"%s\"]/argslist"
 
 # Grub menu stuff
--- a/usr/src/cmd/distro_const/auto_install/ai_sparc_image.xml	Thu Jan 08 13:23:22 2009 -0700
+++ b/usr/src/cmd/distro_const/auto_install/ai_sparc_image.xml	Thu Jan 08 17:06:12 2009 -0800
@@ -538,6 +538,8 @@
 			<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_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>
--- a/usr/src/cmd/distro_const/utils/bootroot_archive.py	Thu Jan 08 13:23:22 2009 -0700
+++ b/usr/src/cmd/distro_const/utils/bootroot_archive.py	Thu Jan 08 17:06:12 2009 -0800
@@ -19,7 +19,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -36,14 +36,18 @@
 import platform
 from subprocess import Popen, PIPE
 from osol_install.ManifestRead import ManifestRead
+from osol_install.install_utils import find
 from osol_install.distro_const.DC_ti import ti_create_target
 from osol_install.distro_const.DC_ti import ti_release_target
 from osol_install.distro_const.dc_utils import get_manifest_value
+from osol_install.distro_const.dc_utils import get_manifest_list
 from osol_install.distro_const.DC_defs import BOOT_ROOT_COMPRESSION_LEVEL
 from osol_install.distro_const.DC_defs import BOOT_ROOT_COMPRESSION_TYPE
 from osol_install.distro_const.DC_defs import BOOT_ROOT_SIZE_PAD
 from osol_install.distro_const.DC_defs import BR_X86_FILENAME
 from osol_install.distro_const.DC_defs import BR_SPARC_FILENAME
+from osol_install.distro_const.DC_defs import \
+    BOOT_ROOT_CONTENTS_BASE_INCLUDE_NOCOMPRESS
 
 execfile('/usr/lib/python2.4/vendor-packages/osol_install/ti_defs.py')
 
@@ -59,7 +63,7 @@
 FIOCOMPRESS = "/usr/sbin/fiocompress"
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-def compress(src,dst):
+def compress(src, dst):
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 	""" fiocompress files in the dst. The files listed in 
 	boot/solaris/filelist.ramdisk and files in usr/kernel are recopied
@@ -76,72 +80,118 @@
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 	os.chdir(src)
-	cmd = FIND + " . > " + TMP_DIR + "/compress_flist"
-	status = os.system(cmd)
-	if (status != 0):
-		raise Exception, (sys.argv[0] + ":Error executing find in " + \
-		    src + " find command returns %d" % status)
-	filelist = open(TMP_DIR + "/compress_flist", 'r')
-	for file in filelist:
+	compress_flist = find(["."])
+	errors = False
+	for file in compress_flist:
 		# strip off the leading ./ and the trailing \n
 		cpio_file = file.lstrip("./").strip()
 
 		if os.access(cpio_file, os.F_OK):
 			# copy all files over to preserve hard links
-			cmd = "echo " + cpio_file + " | " + CPIO + " -pdum " + dst + \
-			    " 2> /dev/null"
+			cmd = "echo " + cpio_file + " | " + CPIO + \
+			    " -pdum " + dst + " 2> /dev/null"
 			status = os.system(cmd)
 			if (status != 0): 
-				break
+				print >>sys.stderr, (sys.argv[0] + ": cpio " +
+				    "error copying file " +  cpio_file +
+				    " to bootroot: " + os.strerror(status >> 8))
+				errors = True
 
-			# If the file is a regular file, has size > 0 and isn't a link,
-			# fiocompress it.
-			stat_out = os.stat(cpio_file)
+			# Compress the file if it is a regular file w/ size > 0
+			stat_out = os.lstat(cpio_file)
 			mode = stat_out.st_mode
-			if stat.S_ISREG(mode) and not stat_out.st_size == 0 and \
-			    not os.path.islink(cpio_file):
-				cmd = FIOCOMPRESS + " -mc " + cpio_file + " " + dst + \
-				    "/" + cpio_file
+			if (stat.S_ISREG(mode) and not (stat_out.st_size == 0)):
+				cmd = FIOCOMPRESS + " -mc " + cpio_file + \
+				    " " + dst + "/" + cpio_file
 				status = os.system(cmd)
 				if (status != 0):
-					break
+					print >>sys.stderr, (sys.argv[0] +
+					    ": error compressing file " +
+					    cpio_file + ": " +
+					    os.strerror(status >> 8))
+			 		errors = True
+	if (errors):
+		raise Exception, (sys.argv[0] + ": Error processing " +
+		    "compressed bootroot files")
 
+	# Re-copy a couple of files we don't want compressed.
+	# Start with the files/dirs in filelist.ramdisk, and append usr/kernel
+	rdfd = open("boot/solaris/filelist.ramdisk", 'r')
+	uc_list = []
+	for filename in rdfd:
+		uc_list.append(filename.strip())
+	rdfd.close()
+	uc_list.append("usr/kernel")
+
+	# Get expanded uncompressed filelist
+	exp_uc_list = find(uc_list)
 
-	filelist.close()
-	try:
-		os.remove(TMP_DIR + "/compress_flist")
-	except:
-		pass
+	# Add (regular) files specified in manifest with fiocompress="false"
+	# Verify that they are non-zero-length, regular files first.
+	manflist = get_manifest_list(manifest_reader_obj,
+	    BOOT_ROOT_CONTENTS_BASE_INCLUDE_NOCOMPRESS)
+	if (len(manflist) > 0):
+		status = 0
+		for nc_file in manflist:
+			try:
+				stat_out = os.lstat(nc_file)
+			except OSError, e:
+				print >>sys.stderr, (sys.argv[0] +
+				    ": Couldn't stat %s to mark as " +
+				    "uncompressed in bootroot: %s") % (
+				    nc_file, e.strerror)
+				status = 1
+				continue
+			mode = stat_out.st_mode
+			if (stat.S_ISREG(mode) and
+			    not (stat_out.st_size == 0)):
+				exp_uc_list.append(nc_file)
+			else:
+				print >>sys.stderr, (sys.argv[0] + ": " +
+				    "Couldn't mark " + nc_file +
+				    " as uncompressed in bootroot: " +
+				    "not a non-zero-sized regular file")
+				status = 1
+		if (status != 0):
+			raise Exception, (sys.argv[0] + ": Error building "
+			    "list of uncompressed bootroot files.")
+
+	# List is now built;  now copy the files.
+	for file in exp_uc_list:
+		cpio_file = file.strip()
+		cmd = "echo " + cpio_file + " | cpio -pdum " + dst + \
+		    " 2> /dev/null"
+		status = os.system(cmd)
+		if (status != 0):
+			print >>sys.stderr, (sys.argv[0] +
+			    ": Error recopying uncompressed file " +
+			    cpio_file + ": " + os.strerror(status >> 8))
+			# Don't skip out on bad status here.
+			# Try whole list before bombing out.
 
 	if (status != 0):
-		raise Exception, (sys.argv[0] + ": Error executing cpio " + \
-		    " cpio command returns %d" % status)
+		raise Exception, (sys.argv[0] +
+		    ": Error recopying uncompressed files to bootroot")
+
 
-	# re-copy a couple of files we don't want compressed.
-	cmd = FIND + \
-	    " `cat boot/solaris/filelist.ramdisk` -type file -print 2> /dev/null > " + \
-	    TMP_DIR + "/uncompress_flist"
-	    
-	status = os.system(cmd)
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+def release_archive():
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	""" Release archive.
 
-	cmd = FIND + " usr/kernel -type file -print 2> /dev/null >> " + \
-	    TMP_DIR + "/uncompress_flist"
-	status = os.system(cmd)
+	Args: None
 
-	flist = open(TMP_DIR + "/uncompress_flist")
-	for file in flist:
-		cpio_file = file.strip()
-		cmd = "echo " + cpio_file + " | cpio -pdum " + dst + " 2> /dev/null"
-		status = os.system(cmd)
-		if (status != 0):
-			flist.close()
-			os.remove(TMP_DIR + "/uncompress_flist")
-			raise Exception, (sys.argv[0] + ": Error executing cpio " + \
-			    " cpio command returns %d" % status)
+	Returns: Status of ti_release_target()
 
-	flist.close()
-	os.remove(TMP_DIR + "/uncompress_flist")
-			
+	Raises: N/A
+	"""
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	return (ti_release_target({
+	    TI_ATTR_TARGET_TYPE:TI_TARGET_TYPE_DC_RAMDISK,
+	    TI_ATTR_DC_RAMDISK_DEST: BR_LOFI_MNT_PT,
+	    TI_ATTR_DC_RAMDISK_FS_TYPE: TI_DC_RAMDISK_FS_TYPE_UFS,
+	    TI_ATTR_DC_RAMDISK_BOOTARCH_NAME: BR_ARCHFILE }))
+
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 def create_target_intr_handler(signum, frame):
@@ -159,17 +209,13 @@
 	"""
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 	print "^C detected.  Cleaning up..."
-	ti_release_target({
-	    TI_ATTR_TARGET_TYPE:TI_TARGET_TYPE_DC_RAMDISK,
-	    TI_ATTR_DC_RAMDISK_DEST: BR_LOFI_MNT_PT,
-	    TI_ATTR_DC_RAMDISK_FS_TYPE: TI_DC_RAMDISK_FS_TYPE_UFS,
-	    TI_ATTR_DC_RAMDISK_BOOTARCH_NAME: BR_ARCHFILE })
+	release_archive()
 	sys.exit(0)
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Main
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-""" Release the bootroot mount and archive the bootroot area.
+""" Archive the bootroot area.
 
 Args:
   MFEST_SOCKET: Socket needed to get manifest data via ManifestRead object
@@ -262,14 +308,10 @@
     TI_ATTR_DC_RAMDISK_BOOTARCH_NAME: BR_ARCHFILE })
 signal.signal (signal.SIGINT, signal.SIG_DFL)
 if (status != 0):
-	ti_release_target({
-	    TI_ATTR_TARGET_TYPE:TI_TARGET_TYPE_DC_RAMDISK,
-	    TI_ATTR_DC_RAMDISK_DEST: BR_LOFI_MNT_PT,
-	    TI_ATTR_DC_RAMDISK_FS_TYPE: TI_DC_RAMDISK_FS_TYPE_UFS,
-	    TI_ATTR_DC_RAMDISK_BOOTARCH_NAME: BR_ARCHFILE })
+	release_archive()
 	raise Exception, (sys.argv[0] +
-	    ": Unable to create boot archive: ti_create_target returned %d" %
-	    status)
+	    ": Unable to create boot archive: ti_create_target returned: " +
+	    os.strerror(status))
 
 # Allow all space to be used.
 # Saving 10% space as typical on UFS buys nothing for a ramdisk.
@@ -277,7 +319,8 @@
 copy_status = os.system(cmd)
 if (copy_status != 0):	# Print a warning and forge ahead anyway...
 	print >>sys.stderr, (
-	    "Warning: Could not tunefs the bootroot to use all space")
+	    "Warning: Could not tunefs the bootroot to use all space:" +
+	    os.strerror(copy_status >> 8))
 
 if is_sparc:
 	etc_system = open(BR_BUILD + "/etc/system", "a+")
@@ -290,28 +333,25 @@
 cmd += FIND + " . | " + CPIO + " -pdum " + BR_LOFI_MNT_PT
 copy_status = os.system(cmd)
 if (copy_status != 0):
-	status = ti_release_target({
-	    TI_ATTR_TARGET_TYPE:TI_TARGET_TYPE_DC_RAMDISK,
-	    TI_ATTR_DC_RAMDISK_DEST: BR_LOFI_MNT_PT,
-	    TI_ATTR_DC_RAMDISK_FS_TYPE: TI_DC_RAMDISK_FS_TYPE_UFS,
-	    TI_ATTR_DC_RAMDISK_BOOTARCH_NAME: BR_ARCHFILE })
+	release_archive()
 	raise Exception, (sys.argv[0] + ": Error copying files to bootroot " +
-	    "container; find/cpio command returns %d" % status)
+	    "container; find/cpio command returns: " +
+	    os.strerror(copy_status >> 8))
 
 if is_sparc:
 	print "Doing compression..."
-	compress(BR_BUILD, BR_LOFI_MNT_PT)
+	try:
+		compress(BR_BUILD, BR_LOFI_MNT_PT)
+	except Exception, e:
+		release_archive()
+		raise
 
 # Unmount the bootroot file and delete the lofi device
-status = ti_release_target({
-    TI_ATTR_TARGET_TYPE:TI_TARGET_TYPE_DC_RAMDISK,
-    TI_ATTR_DC_RAMDISK_DEST: BR_LOFI_MNT_PT,
-    TI_ATTR_DC_RAMDISK_FS_TYPE: TI_DC_RAMDISK_FS_TYPE_UFS,
-    TI_ATTR_DC_RAMDISK_BOOTARCH_NAME: BR_ARCHFILE })
+status = release_archive()
 if (status != 0):
 	raise Exception, (sys.argv[0] +
-	    ": Unable to release boot archive: ti_release_target returned %d" %
-	    status)
+	    ": Unable to release boot archive: ti_release_target returned: " +
+	    os.strerror(status))
 
 # We did the sparc compression above, now do it for x86
 if not is_sparc:
@@ -325,22 +365,24 @@
 		if (BR_COMPR_TYPE == "gzip"):
 			cmd += "-tgzip -mx=" + BR_COMPR_LEVEL + " "
 		else:
-			raise Exception, (sys.argv[0] + ": Unrecognized bootroot " +
+			raise Exception, (sys.argv[0] + \
+			    ": Unrecognized bootroot " +
 			    "compression type: " + BR_COMPR_TYPE)
 		cmd += BR_ARCHFILE + ".gz " + BR_ARCHFILE
 		status = os.system(cmd)
 		if (status != 0):
 			raise Exception, (sys.argv[0] +
 			    ": Error compressing bootroot: " +
-			    "7za command returns %d" % status)
+			    "7za command returns: " + os.strerror(status >> 8))
 
 		# move compressed file to proper location in pkg image area
 		mvcmd = MV + " " + BR_ARCHFILE + ".gz " + BR_ARCHFILE
 		status = os.system(mvcmd)
 		if (status != 0):
 			raise Exception, (sys.argv[0] + ": Error moving " +
-			    "bootroot from %s to %s: mv returns %d" %
-			    (BR_ARCHFILE + '.gz', BR_ARCHFILE, status))
+			    "bootroot from %s to %s: %s" %
+			    (BR_ARCHFILE + '.gz', BR_ARCHFILE,
+			    os.strerror(status >> 8)))
 
 os.chmod(BR_ARCHFILE, 0644)
 
--- a/usr/src/lib/install_utils/install_utils.py	Thu Jan 08 13:23:22 2009 -0700
+++ b/usr/src/lib/install_utils/install_utils.py	Thu Jan 08 17:06:12 2009 -0800
@@ -18,12 +18,13 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
 import sys
 import os
+import stat
 import errno
 import select
 from subprocess import *
@@ -371,7 +372,6 @@
 	  IOError with errno = EINVAL: mode argument is invalid
 	"""
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-def canaccess(filename, mode):
 
 	# Don't try opening file with mode "w", else file will be truncated.
 	if (mode == "rw"):
@@ -452,3 +452,112 @@
 				log.log(stderr_log_level, output)
 
 	return (p.wait())
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+def __find_error_handler(raise_me):
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	"""Error handler for find() below.  Raises the exception passed to it.
+
+	Args:
+	  raise_me: Exception to raise
+
+	Returns: None
+
+	Raises: The exception passed in.
+	"""
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	raise raise_me
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+def find(rootpaths, type=None, raise_errors=False):
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	"""Python implementation of the Unix find(1) command.
+
+	Order of output is similar, but not the same as, find(1) when -depth
+	is not passed to it.  A directory is enumerated before the files it
+	contains.
+
+	Unlike find(1), no errors are returned when given a file or directory
+	to parse which doesn't exist (when raise_errors is False)
+
+	Args:
+	  rootpaths: list of file and/or directory pathnames to parse.
+
+	  type:
+		- When set to None, return all found pathnames.
+		- When set to "dir", return all found directories only.  This
+			does not include links to directories.
+		- When set to "file", return all found files only.  This does
+			not include links to files.
+
+	 raise_errors:
+		- When set to True: raise an OSError when a non-existant file
+			or directory to parse is passed in the rootpaths list.
+		- When set to False, ignore any such errors.
+	"""
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	rlist = []
+	error_handler = None
+
+	if ((type != None) and (type != "dir") and (type != "file")):
+		raise Exception, (
+		    "find: \"type\" must be None, \"dir\" or \"file\"")
+
+	if (raise_errors):
+		error_handler = __find_error_handler
+
+	for rootpath in rootpaths:
+
+		try:
+			stat_out = os.lstat(rootpath)
+		except OSError:		# Doesn't exist
+			continue
+
+		# Handle case where rootpath is not a proper directory.
+		# (Links to directories are not proper directories.)
+		if ((type == None) and (not stat.S_ISDIR(stat_out.st_mode))):
+			rlist.append(rootpath)
+			continue
+
+		# Print rootpath only if a proper file, if type == "file"
+		elif (type == "file"):
+			if (stat.S_ISREG(stat_out.st_mode)):
+				rlist.append(rootpath)
+			continue
+
+		for path, subdirs, files in os.walk(rootpath, True,
+		    error_handler):
+
+			# Take the path if we're taking everything, or if
+			# type == dir and path is a proper directory (not link)
+			if ((type == None) or
+			    ((type == "dir") and
+			    (stat.S_ISDIR(stat_out.st_mode)))):
+				rlist.append(path)
+
+			# Only the directory is desired.
+			if (type == "dir"):
+				continue
+
+			# If names listed in subdirs are not directories (e.g.
+			# they are symlinks), append them if type is None,
+			# like what find(1) does.  If they are dirs, then
+			# os.walk will get them on the next pass.
+			if (type == None):
+				for subdir in subdirs:
+					fullname = path + "/" + subdir
+					stat_out = os.lstat(fullname)
+					if (not stat.S_ISDIR(stat_out.st_mode)):
+						rlist.append(fullname)
+
+			for file in files:
+				fullname = path + "/" + file
+				# Check for a proper file if (type == "file")
+				if (type == "file"):
+					stat_out = os.lstat(fullname)
+					if (not stat.S_ISREG(stat_out.st_mode)):
+						continue
+				rlist.append(fullname)
+	return rlist