18688 pkg clients shouldn't attempt to find an image at startup
authorShawn Walker <shawn.walker@oracle.com>
Wed, 03 Aug 2011 12:56:59 -0700
changeset 2488 010931d9cabe
parent 2487 7ae6c921aed3
child 2489 b88b784696df
18688 pkg clients shouldn't attempt to find an image at startup 2856 image.py's imgdir and root properties should be readonly 18666 pkg traceback if current working directory unreadable by current user 18694 pkg(1) -R option description needs updating
doc/client_api_versions.txt
src/client.py
src/gui/modules/misc_non_gui.py
src/man/pkg.1.txt
src/man/pkgdepend.1.txt
src/modules/client/api.py
src/modules/client/api_errors.py
src/modules/client/image.py
src/modules/lint/engine.py
src/pkgdep.py
src/sysrepo.py
src/tests/cli/t_pkg_R_option.py
src/tests/cli/t_pkg_install.py
src/tests/pkg5unittest.py
src/util/distro-import/importer.py
--- a/doc/client_api_versions.txt	Tue Aug 02 11:56:50 2011 -0700
+++ b/doc/client_api_versions.txt	Wed Aug 03 12:56:59 2011 -0700
@@ -1,3 +1,12 @@
+Version 64:
+Incompatible with clients using versions 0-63.
+
+    pkg.client.api_errors has changed as follows:
+       * The ImageLocationAmbiguous exception has been removed.  The client
+         API no longer requires the image to be found at '/' on Solaris.
+         Clients are free to enforce whatever restrictions on image root
+         they desire.
+
 Version 63:
 Compatible with clients using version 62.
 
@@ -38,7 +47,7 @@
     pkg.client.api.PlanDescription has changed as follows:
         * Added the following new interfaces
                 get_bytes_added()
-		get_cbytes_added()
+                get_cbytes_added()
                 get_bytes_avail()
                 get_cbytes_avail()
     pkg.client.api.prepare has changed as follows:
@@ -596,23 +605,23 @@
 Incompatible with clients using versions 0-23.
     The pkg.client.api module has changed as follows:
         * plan_install no longer takes a filters argument
-	* plan_change_variant changed to plan_change_varcets.
-	  w/ argument list changes.
-	* Added get_pub_search_order
-	* Added set_pub_search_after
-	* Added set_pub_search_before
+        * plan_change_variant changed to plan_change_varcets.
+          w/ argument list changes.
+        * Added get_pub_search_order
+        * Added set_pub_search_after
+        * Added set_pub_search_before
 
 Version 23:
 Incompatible with clients using versions 0-22.
     The pkg.client.api module has changed as follows:
         * PackageInfo objects no longer take a "state" parameter, but a
-	  "states" parameter, and the corresponding "state" member is now
-	  "states", and is a list of states, rather than a single value.
+          "states" parameter, and the corresponding "state" member is now
+          "states", and is a list of states, rather than a single value.
 
 Version 22:
 Compatible with clients using version 21.
 Changes:
-	Adds the description field to the PackageInfo class.
+        Adds the description field to the PackageInfo class.
 
 Version 21:
 Incompatible with clients using versions 0-20.
--- a/src/client.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/client.py	Wed Aug 03 12:56:59 2011 -0700
@@ -72,6 +72,7 @@
         import pkg.client.publisher as publisher
         import pkg.fmri as fmri
         import pkg.misc as misc
+        import pkg.portable as portable
         import pkg.version as version
 
         from pkg.client import global_settings
@@ -89,7 +90,7 @@
         import sys
         sys.exit(1)
 
-CLIENT_API_VERSION = 63
+CLIENT_API_VERSION = 64
 PKG_CLIENT_NAME = "pkg"
 
 JUST_UNKNOWN = 0
@@ -1253,27 +1254,6 @@
                 return api.ImageInterface(imgdir, CLIENT_API_VERSION,
                     progresstracker, None, PKG_CLIENT_NAME,
                     exact_match=exact_match, runid=runid)
-        except api_errors.ImageLocationAmbiguous, e:
-                # This should only be raised if exact_match is False.
-                assert exact_match is False
-                error(e)
-                if pkg_image_used:
-                        logger.error(_("(Image location set by $PKG_IMAGE.)"))
-                # This attempts to rebuild the pkg command so users can
-                # just copy & paste the correct one, but it can't perfectly
-                # handle all possible shell escaping requirements or detect
-                # executions using sudo, pfexec, etc.  It's a best effort
-                # convenience feature.
-                logger.error(_("""
-To use this image, execute pkg again as follows:
-
-pkg -R %(root)s %(args)s
-
-To use the system image, execute pkg again as follows:
-
-pkg -R / %(args)s
-""") % { "root": qv(e.root), "args": " ".join(map(qv, sys.argv[1:]))})
-                return
         except api_errors.ImageNotFoundException, e:
                 if e.user_specified:
                         if pkg_image_used:
@@ -5825,12 +5805,14 @@
         provided_image_dir = True
         pkg_image_used = False
         if "mydir" not in locals():
-                try:
-                        mydir = os.environ["PKG_IMAGE"]
+                mydir, provided_image_dir = api.get_default_image_root(
+                    orig_cwd=orig_cwd)
+                if os.environ.get("PKG_IMAGE"):
+                        # It's assumed that this has been checked by the above
+                        # function call and hasn't been removed from the
+                        # environment.
                         pkg_image_used = True
-                except KeyError:
-                        provided_image_dir = False
-                        mydir = orig_cwd
+
         if not mydir:
                 error(_("Could not find image.  Use the -R option or set "
                     "$PKG_IMAGE to the\nlocation of an image."))
--- a/src/gui/modules/misc_non_gui.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/gui/modules/misc_non_gui.py	Wed Aug 03 12:56:59 2011 -0700
@@ -41,7 +41,7 @@
 
 # The current version of the Client API the PM, UM and
 # WebInstall GUIs have been tested against and are known to work with.
-CLIENT_API_VERSION = 63
+CLIENT_API_VERSION = 64
 LOG_DIR = "/var/tmp"
 LOG_ERROR_EXT = "_error.log"
 LOG_INFO_EXT = "_info.log"
--- a/src/man/pkg.1.txt	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/man/pkg.1.txt	Wed Aug 03 12:56:59 2011 -0700
@@ -42,7 +42,7 @@
      /usr/bin/pkg mediator [-aH] [-F format] [<mediator> ...]
      /usr/bin/pkg set-mediator [-nv] [-I <implementation>] [-V <version>]
          [--no-be-activate] [--deny-new-be | --require-new-be]
-	 [--be-name name] <mediator> ...
+         [--be-name name] <mediator> ...
      /usr/bin/pkg unset-mediator [-nvIV] [--no-be-activate]
          [--deny-new-be | --require-new-be] [--be-name name] <mediator> ...
 
@@ -77,7 +77,7 @@
          [-p repo_uri] [--enable] [--disable] [--no-refresh]
          [--reset-uuid] [--non-sticky] [--sticky]
          [--search-after=publisher] [--search-before=publisher]
-         [--search-first] 
+         [--search-first]
          [--approve-ca-cert=path_to_CA]
          [--revoke-ca-cert=hash_of_CA_to_remove]
          [--unset-ca-cert=hash_of_CA_to_remove]
@@ -144,11 +144,9 @@
      The following options are supported:
 
      -R dir
-          Operate on the image rooted at dir, rather than the one discovered
-          automatically.  By default, pkg(1) attempts to determine, based on
-          its working directory, in what image it has been invoked.  If no
-          image metadata can be found in the parent directories, the
-          invocation will fail.  See also ENVIRONMENT VARIABLES.
+          Operate on the image rooted at directory dir.  If no directory
+          was specified or determined based on environment, the default is
+          '/'.  See also ENVIRONMENT VARIABLES.
 
      --help or -?
           Displays a usage message.
--- a/src/man/pkgdepend.1.txt	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/man/pkgdepend.1.txt	Wed Aug 03 12:56:59 2011 -0700
@@ -57,11 +57,9 @@
      The following options are supported:
 
      -R dir
-          Operate on the image rooted at dir, rather than the one discovered
-          automatically.  By default, pkgdepend(1) attempts to determine,
-          based on its working directory, in what image it has been invoked.
-          If no image metadata can be found in the parent directories, the
-          invocation will fail.  See also ENVIRONMENT VARIABLES.
+          Operate on the image rooted at dir.  If no dir was specified or
+          determined based on environment, the default is '/'.  See also
+          ENVIRONMENT VARIABLES.
 
      --help or -?
           Displays a usage message.
--- a/src/modules/client/api.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/modules/client/api.py	Wed Aug 03 12:56:59 2011 -0700
@@ -73,7 +73,7 @@
 from pkg.client.pkgdefs import *
 from pkg.smf import NonzeroExitException
 
-CURRENT_API_VERSION = 63
+CURRENT_API_VERSION = 64
 CURRENT_P5I_VERSION = 1
 
 # Image type constants.
@@ -279,13 +279,10 @@
                 attempt to find a usable image starting from the specified
                 directory, going up to the filesystem root until it finds one.
                 If set to True, an image must exist at the location indicated
-                by 'img_path'.  If set to False for a client running on the
-                Solaris platform, an ImageLocationAmbiguous exception will be
-                raised if an image is found somewhere other than '/'.  For all
-                other platforms, a value of False will allow any image location.
+                by 'img_path'.
                 """
 
-                compatible_versions = set([62, CURRENT_API_VERSION])
+                compatible_versions = set([CURRENT_API_VERSION])
 
                 if version_id not in compatible_versions:
                         raise apx.VersionException(CURRENT_API_VERSION,
@@ -4636,6 +4633,46 @@
                 return self.__plan.cbytes_avail
 
 
+def get_default_image_root(orig_cwd=None):
+        """Returns a tuple of (root, exact_match) where 'root' is the absolute
+        path of the default image root based on current environment given the
+        client working directory and platform defaults, and 'exact_match' is a
+        boolean specifying how the default should be treated by ImageInterface.
+        Note that the root returned may not actually be the valid root of an
+        image; it is merely the default location a client should use when
+        initializing an ImageInterface (e.g. '/' is not a valid image on Solaris
+        10).
+
+        The ImageInterface object will use the root provided as a starting point
+        to find an image, searching upwards through each parent directory until
+        '/' is reached based on the value of exact_match.
+
+        'orig_cwd' should be the original current working directory at the time
+        of client startup.  This value is assumed to be valid if provided,
+        although permission and access errors will be gracefully handled.
+        """
+
+        # If an image location wasn't explicitly specified, check $PKG_IMAGE in
+        # the environment.
+        root = os.environ.get("PKG_IMAGE")
+        exact_match = True
+        if not root:
+                if os.environ.get("PKG_FIND_IMAGE") or \
+                    portable.osname != "sunos":
+                        # If no image location was found in the environment,
+                        # then see if user enabled finding image or if current
+                        # platform isn't Solaris.  If so, attempt to find the
+                        # image starting with the working directory.
+                        root = orig_cwd
+                        if root:
+                                exact_match = False
+                if not root:
+                        # If no image directory has been determined based on
+                        # request or environment, default to live root.
+                        root = misc.liveroot()
+        return root, exact_match
+
+
 def image_create(pkg_client_name, version_id, root, imgtype, is_zone,
     cancel_state_callable=None, facets=misc.EmptyDict, force=False,
     mirrors=misc.EmptyI, origins=misc.EmptyI, prefix=None, refresh_allowed=True,
--- a/src/modules/client/api_errors.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/modules/client/api_errors.py	Wed Aug 03 12:56:59 2011 -0700
@@ -99,24 +99,6 @@
                 self.root_dir = root_dir
 
 
-class ImageLocationAmbiguous(ApiException):
-        """Used to indicate that an image was found at a location other than
-        '/' on the Solaris platform when requesting automatic image location
-        discovery.  Clients should trap this exception and add their own
-        messaging telling the user how to specify an image root explicitly
-        for the location."""
-
-        def __init__(self, root, live_root="/"):
-                ApiException.__init__(self)
-                self.root = root
-                self.live_root = live_root
-
-        def __str__(self):
-                return _("pkg(5) image found at '%(found)s' instead of "
-                    "'%(expected)s'.") % { "found": self.root,
-                    "expected": self.live_root }
-
-
 class ImageFormatUpdateNeeded(ApiException):
         """Used to indicate that an image cannot be used until its format is
         updated."""
--- a/src/modules/client/image.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/modules/client/image.py	Wed Aug 03 12:56:59 2011 -0700
@@ -161,8 +161,7 @@
         def __init__(self, root, user_provided_dir=False, progtrack=None,
             should_exist=True, imgtype=None, force=False,
             augment_ta_from_parent_image=True, allow_ondisk_upgrade=None,
-            allow_ambiguous=False, props=misc.EmptyDict, cmdpath=None,
-            runid=-1):
+            props=misc.EmptyDict, cmdpath=None, runid=-1):
 
                 if should_exist:
                         assert(imgtype is None)
@@ -204,22 +203,22 @@
                 # Indicates whether automatic image format upgrades of the
                 # on-disk format are allowed.
                 self.allow_ondisk_upgrade = allow_ondisk_upgrade
-                self.allow_ambiguous = allow_ambiguous
                 self.__upgraded = False
 
                 # Must happen after upgraded assignment.
                 self.__init_catalogs()
 
+                self.__imgdir = None
+                self.__root = root
+
                 self.attrs = { "Build-Release": "5.11" } # XXX real data needed
                 self.blocking_locks = False
                 self.cfg = None
                 self.history = history.History()
                 self.imageplan = None
                 self.img_prefix = None
-                self.imgdir = None
                 self.index_dir = None
                 self.plandir = None
-                self.root = root
                 self.version = -1
 
                 # Can have multiple read cache dirs...
@@ -291,17 +290,6 @@
 
                 self.augment_ta_from_parent_image = augment_ta_from_parent_image
 
-        @property
-        def write_cache_path(self):
-                """Returns a path to fs that holds write cache - used to
-                compute whether we have sufficent space for downloads"""
-                return self.__user_cache_dir or \
-                    os.path.join(self.imgdir, IMG_PUB_DIR)
-
-        @staticmethod
-        def alloc(*args, **kwargs):
-                return Image(*args, **kwargs)
-
         def __catalog_loaded(self, name):
                 """Returns a boolean value indicating whether the named catalog
                 has already been loaded.  This is intended to be used as an
@@ -322,9 +310,30 @@
                 self.__catalogs = {}
                 self.__alt_pkg_sources_loaded = False
 
+        @staticmethod
+        def alloc(*args, **kwargs):
+                return Image(*args, **kwargs)
+
+        @property
+        def imgdir(self):
+                """The absolute path of the image's metadata."""
+                return self.__imgdir
+
+        @property
+        def locked(self):
+                """A boolean value indicating whether the image is currently
+                locked."""
+
+                return self.__lock and self.__lock.locked
+
+        @property
+        def root(self):
+                """The absolute path of the image's location."""
+                return self.__root
+
         @property
         def signature_policy(self):
-                """Returns the signature policy for this image."""
+                """The current signature policy for this image."""
 
                 if self.__sig_policy is not None:
                         return self.__sig_policy
@@ -336,10 +345,10 @@
 
         @property
         def trust_anchors(self):
-                """Return a dictionary mapping subject hashes for certificates
-                this image trusts to those certs.  The image trusts those
-                trust anchors in its trust_anchor_dir and those in the from
-                which pkg was run."""
+                """A dictionary mapping subject hashes for certificates this
+                image trusts to those certs.  The image trusts the trust anchors
+                in its trust_anchor_dir and those in the image from which the
+                client was run."""
 
                 if self.__trust_anchors is not None:
                         return self.__trust_anchors
@@ -354,7 +363,6 @@
                 if self.__cmddir and self.augment_ta_from_parent_image:
                         pkg_trust_anchors = Image(self.__cmddir,
                             augment_ta_from_parent_image=False,
-                            allow_ambiguous=True,
                             cmdpath=self.cmdpath).trust_anchors
                 if not loc_is_dir and os.path.exists(trust_anchor_loc):
                         raise apx.InvalidPropertyValue(_("The trust "
@@ -381,11 +389,11 @@
                 return self.__trust_anchors
 
         @property
-        def locked(self):
-                """Returns a boolean value indicating whether the image is
-                currently locked."""
-
-                return self.__lock and self.__lock.locked
+        def write_cache_path(self):
+                """The path to the filesystem that holds the write cache--used
+                to compute whether sufficent space is available for downloads."""
+                return self.__user_cache_dir or \
+                    os.path.join(self.imgdir, IMG_PUB_DIR)
 
         @contextmanager
         def locked_op(self, op, allow_unprivileged=False, new_history_op=True):
@@ -533,20 +541,6 @@
                                     os.path.realpath(d):
                                         raise apx.ImageNotFoundException(
                                             exact_match, startd, d)
-                                live_root = misc.liveroot()
-                                if not exact_match and d != live_root and \
-                                    not self.allow_ambiguous and \
-                                    portable.osname == "sunos":
-                                        # On Solaris, consider an image found
-                                        # somewhere other than the live root an
-                                        # an error if an exact match wasn't
-                                        # requested.  (This prevents accidental
-                                        # use of nested images.) It is not
-                                        # desirable to do this on other
-                                        # platforms as non-root images are the
-                                        # norm.
-                                        raise apx.ImageLocationAmbiguous(d,
-                                            live_root=live_root)
                                 self.__set_dirs(imgtype=imgtype, root=d,
                                     startd=startd, progtrack=progtrack)
                                 return
@@ -752,8 +746,8 @@
                            attempted.\nliveroot: %s\nimage path: %s" % \
                            (misc.liveroot(), startd)
 
+                self.__root = root
                 self.type = imgtype
-                self.root = root
                 if self.type == IMG_USER:
                         self.img_prefix = img_user_prefix
                 else:
@@ -765,10 +759,21 @@
 
                 # cleanup specified path
                 if os.path.isdir(root):
-                        cwd = os.getcwd()
-                        os.chdir(root)
-                        self.root = os.getcwd()
-                        os.chdir(cwd)
+                        try:
+                                cwd = os.getcwd()
+                        except Exception, e:
+                                # If current directory can't be obtained for any
+                                # reason, ignore the error.
+                                cwd = None
+
+                        try:
+                                os.chdir(root)
+                                self.__root = os.getcwd()
+                        except EnvironmentError, e:
+                                raise apx._convert_error(e)
+                        finally:
+                                if cwd:
+                                        os.chdir(cwd)
 
                 # If current image is locked, then it should be unlocked
                 # and then relocked after the imgdir is changed.  This
@@ -778,7 +783,7 @@
                         self.unlock()
 
                 # Must set imgdir first.
-                self.imgdir = os.path.join(self.root, self.img_prefix)
+                self.__imgdir = os.path.join(self.root, self.img_prefix)
 
                 # Force a reset of version.
                 self.version = -1
@@ -4188,8 +4193,8 @@
                         # workspace, for example.
                         #
                         newimg = Image(self.__cmddir,
-                            allow_ondisk_upgrade=False, allow_ambiguous=True,
-                            progtrack=progtrack, cmdpath=self.cmdpath)
+                            allow_ondisk_upgrade=False, progtrack=progtrack,
+                            cmdpath=self.cmdpath)
                         useimg = True
                         if refresh_allowed:
                                 # If refreshing publisher metadata is allowed,
--- a/src/modules/lint/engine.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/modules/lint/engine.py	Wed Aug 03 12:56:59 2011 -0700
@@ -39,7 +39,7 @@
 import sys
 
 PKG_CLIENT_NAME = "pkglint"
-CLIENT_API_VERSION = 63
+CLIENT_API_VERSION = 64
 pkg.client.global_settings.client_name = PKG_CLIENT_NAME
 
 class LintEngineException(Exception):
--- a/src/pkgdep.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/pkgdep.py	Wed Aug 03 12:56:59 2011 -0700
@@ -42,7 +42,7 @@
 import pkg.publish.dependencies as dependencies
 from pkg.misc import msg, emsg, PipeError
 
-CLIENT_API_VERSION = 63
+CLIENT_API_VERSION = 64
 PKG_CLIENT_NAME = "pkgdepend"
 
 DEFAULT_SUFFIX = ".res"
@@ -249,20 +249,21 @@
         provided_image_dir = True
         pkg_image_used = False
         if img_dir == None:
+                orig_cwd = None
                 try:
-                        img_dir = os.environ["PKG_IMAGE"]
+                        orig_cwd = os.getcwd()
+                except OSError:
+                        # May be unreadable by user or have other problem.
+                        pass
+
+                img_dir, provided_image_dir = api.get_default_image_root(
+                    orig_cwd=orig_cwd)
+                if os.environ.get("PKG_IMAGE"):
+                        # It's assumed that this has been checked by the above
+                        # function call and hasn't been removed from the
+                        # environment.
                         pkg_image_used = True
-                except KeyError:
-                        provided_image_dir = False
-                        try:
-                                img_dir = os.getcwd()
-                        except OSError, e:
-                                try:
-                                        img_dir = os.environ["PWD"]
-                                        if not img_dir or img_dir[0] != "/":
-                                                img_dir = None
-                                except KeyError:
-                                        img_dir = None
+
         if not img_dir:
                 error(_("Could not find image.  Use the -R option or set "
                     "$PKG_IMAGE to the\nlocation of an image."))
@@ -275,34 +276,6 @@
                 api_inst = api.ImageInterface(img_dir, CLIENT_API_VERSION,
                     progress.QuietProgressTracker(), None, PKG_CLIENT_NAME,
                     exact_match=provided_image_dir)
-        except api_errors.ImageLocationAmbiguous, e:
-                def qv(val):
-                        # Escape shell metacharacters; '\' must be escaped first
-                        # to prevent escaping escapes.
-                        for c in "\\ \t\n'`;&()|^<>?*":
-                                val = val.replace(c, "\\" + c)
-                        return val
-
-                # This should only be raised if exact_match is False.
-                assert provided_image_dir is False
-                error(e)
-                if pkg_image_used:
-                        emsg(_("(Image location set by $PKG_IMAGE.)"))
-                # This attempts to rebuild the pkgdepend command so users can
-                # just copy & paste the correct one, but it can't perfectly
-                # handle all possible shell escaping requirements or detect
-                # executions using sudo, pfexec, etc.  It's a best effort
-                # convenience feature.
-                emsg(_("""
-To use this image, execute pkgdepend again as follows:
-
-pkgdepend -R %(root)s %(args)s
-
-To use the system image, execute pkgdepend again as follows:
-
-pkgdepend -R / %(args)s
-""") % { "root": qv(e.root), "args": " ".join(map(qv, sys.argv[1:]))})
-                return 1
         except api_errors.ImageNotFoundException, e:
                 if e.user_specified:
                         if pkg_image_used:
--- a/src/sysrepo.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/sysrepo.py	Wed Aug 03 12:56:59 2011 -0700
@@ -53,7 +53,7 @@
 orig_cwd = None
 
 PKG_CLIENT_NAME = "pkg.sysrepo"
-CLIENT_API_VERSION = 63
+CLIENT_API_VERSION = 64
 pkg.client.global_settings.client_name = PKG_CLIENT_NAME
 
 # exit codes
--- a/src/tests/cli/t_pkg_R_option.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/tests/cli/t_pkg_R_option.py	Wed Aug 03 12:56:59 2011 -0700
@@ -24,7 +24,7 @@
 
 import testutils
 if __name__ == "__main__":
-	testutils.setup_environment("../../../proto")
+        testutils.setup_environment("../../../proto")
 import pkg5unittest
 
 import os
@@ -45,11 +45,11 @@
                 self.pkgsend_bulk(self.rurl, self.foo10)
                 self.image_create(self.rurl)
 
-	def test_bad_cli_options(self):
+        def test_bad_cli_options(self):
                 """Verify that pkg rejects invalid -R combos and values."""
 
-		self.pkg("-@", exit=2)
-		self.pkg("-s status", exit=2)
+                self.pkg("-@", exit=2)
+                self.pkg("-s status", exit=2)
                 self.pkg("-R status", exit=2)
                 self.pkg("-R / version", exit=2)
 
@@ -97,7 +97,7 @@
                 self.assertEqual(os.getcwd(), self.img_path())
 
                 if portable.osname != "sunos":
-                        # For other platforms, first install a package uses an
+                        # For other platforms, first install a package using an
                         # explicit root, and then verify that an implicit find
                         # of the image results in the right image being found.
                         self.pkg("install foo")
@@ -106,13 +106,30 @@
                         # Remaining tests are not valid on other platforms.
                         return
 
-                # Should fail because image found is not at '/', but at cwd().
-                self.pkg("install foo", exit=1, use_img_root=False)
+                # Should fail because live root is not an image (Solaris 10
+                # case), even though CWD contains a valid one since
+                # PKG_FIND_IMAGE was not set in environment.
+                bad_live_root = os.path.join(self.test_root, "test_2_implicit")
+                os.mkdir(bad_live_root)
+                self.pkg("-D simulate_live_root=%s install foo " % bad_live_root,
+                     use_img_root=False, exit=1)
 
-                # Should succeed because image is found at simulated live root.
+                # Should succeed because image is found at simulated live root,
+                # even though one does not exist in CWD.
+                os.chdir(self.test_root)
                 self.pkg("-D simulate_live_root=%s install foo" %
                     self.img_path(), use_img_root=False)
 
+                # Should succeed because image is found using CWD and
+                # PKG_FIND_IMAGE was set in environment, even though live root
+                # is not a valid image.
+                os.environ["PKG_FIND_IMAGE"] = "true"
+                os.chdir(self.img_path())
+                self.pkg("-D simulate_live_root=%s uninstall foo" %
+                     bad_live_root, use_img_root=False)
+                del os.environ["PKG_FIND_IMAGE"]
+                os.chdir(self.test_root)
+
 
 if __name__ == "__main__":
         unittest.main()
--- a/src/tests/cli/t_pkg_install.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/tests/cli/t_pkg_install.py	Wed Aug 03 12:56:59 2011 -0700
@@ -4819,69 +4819,6 @@
 
                 self.pkg("install [email protected]")
 
-        # Tests for checking what happens when two images are installed side by
-        # side.
-        def test_var_pkg_missing_cfg_cache_ospkg_also_missing_alongside(self):
-                """ Each bad_dir is missing a cfg_cache
-                These 3 tests do nothing currently because trying to install an
-                image next to an existing image in not currently possible.  The
-                test cases remain against the day that such an arrangement is
-                possible.
-                """
-
-                self.pkgsend_bulk(self.rurl, self.foo11)
-                self.image_create(self.rurl)
-
-                self.dir = self.corrupt_image_create(self.rurl,
-                    set(["cfg_cache_absent"]), [".org.opensolaris,pkg"])
-                self.dir = self.corrupt_image_create(self.rurl,
-                    set(["cfg_cache_absent"]), ["var/pkg"], destroy=False)
-
-                self.pkg("-D simulate_live_root=%s install [email protected]" %
-                    self.backup_img_path(), use_img_root=False)
-
-        def test_var_pkg_ospkg_missing_cfg_cache_alongside(self):
-                """ Complete Full image besides a User image missing cfg_cache
-                """
-
-                self.pkgsend_bulk(self.rurl, self.foo11)
-                self.image_create(self.rurl)
-
-                self.dir = self.corrupt_image_create(self.rurl, set(),
-                    ["var/pkg"])
-                img_path = self.get_img_path()
-                self.dir = self.corrupt_image_create(self.rurl,
-                    set(["cfg_cache_absent"]), [".org.opensolaris,pkg"],
-                    destroy=False)
-
-                # Found full image before we reached root image.
-                self.pkg("-D simulate_live_root=%s install [email protected]" %
-                    self.backup_img_path(), use_img_root=False, exit=1)
-
-                # Only possible if user specifies full image's root since
-                # user image is at the top level.
-                self.pkg("-R %s install [email protected]" % img_path)
-
-        def test_var_pkg_missing_cfg_cache_ospkg_alongside(self):
-                """ Complete User image besides a Full image missing cfg_cache
-                """
-
-                self.pkgsend_bulk(self.rurl, self.foo11)
-                self.image_create(self.rurl)
-
-                self.dir = self.corrupt_image_create(self.rurl,
-                    set(["cfg_cache_absent"]), ["var/pkg"])
-                self.dir = self.corrupt_image_create(self.rurl, set(),
-                    [".org.opensolaris,pkg"], destroy=False)
-
-                # Found user image before we reached root image.
-                self.pkg("-D simulate_live_root=%s install [email protected]" %
-                    self.backup_img_path(), use_img_root=False, exit=1)
-
-                # Should succeed and install package in user image since
-                # test suite will add -R self.get_img_path().
-                self.pkg("install [email protected]")
-
 
 class TestPkgInstallObsolete(pkg5unittest.SingleDepotTestCase):
         """Test cases for obsolete packages."""
--- a/src/tests/pkg5unittest.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/tests/pkg5unittest.py	Wed Aug 03 12:56:59 2011 -0700
@@ -127,7 +127,7 @@
 
 # Version test suite is known to work with.
 PKG_CLIENT_NAME = "pkg"
-CLIENT_API_VERSION = 63
+CLIENT_API_VERSION = 64
 
 ELIDABLE_ERRORS = [ TestSkippedException, depotcontroller.DepotStateException ]
 
@@ -2436,7 +2436,7 @@
                 return self.__imgs_path_backup[self.img_index()]
 
         def corrupt_image_create(self, repourl, config, subdirs, prefix="test",
-            destroy = True):
+            destroy=True):
                 """ Creates two levels of directories under the original image
                 directory. In the first level (called bad), it builds a "corrupt
                 image" which means it builds subdirectories the subdirectories
--- a/src/util/distro-import/importer.py	Tue Aug 02 11:56:50 2011 -0700
+++ b/src/util/distro-import/importer.py	Wed Aug 03 12:56:59 2011 -0700
@@ -56,7 +56,7 @@
 from pkg.misc import emsg
 from pkg.portable import PD_LOCAL_PATH, PD_PROTO_DIR, PD_PROTO_DIR_LIST
 
-CLIENT_API_VERSION = 63
+CLIENT_API_VERSION = 64
 PKG_CLIENT_NAME = "importer.py"
 pkg.client.global_settings.client_name = PKG_CLIENT_NAME