GK: Restore changeset cfbbedf29419
authorKeith Mitchell <keith.mitchell@oracle.com>
Mon, 30 Aug 2010 15:53:34 -0700
changeset 870 1cd031050724
parent 869 424db5e50fb5
child 872 8b098e92c2a9
GK: Restore changeset cfbbedf29419
usr/src/Makefile.buildnum
usr/src/cmd/auto-install/auto_ddu_lib.c
usr/src/cmd/auto-install/auto_install.c
usr/src/cmd/auto-install/auto_install.h
usr/src/cmd/auto-install/default.xml
--- a/usr/src/Makefile.buildnum	Mon Aug 30 15:52:14 2010 -0700
+++ b/usr/src/Makefile.buildnum	Mon Aug 30 15:53:34 2010 -0700
@@ -36,4 +36,4 @@
 # currently open build in the slim_source repository.
 #
 
-INSTALL_BUILDNUM= 147
+INSTALL_BUILDNUM= 148
--- a/usr/src/cmd/auto-install/auto_ddu_lib.c	Mon Aug 30 15:52:14 2010 -0700
+++ b/usr/src/cmd/auto-install/auto_ddu_lib.c	Mon Aug 30 15:53:34 2010 -0700
@@ -39,26 +39,39 @@
 #define	DDU_PACKAGE_MODULE	"DDU.ddu_package"
 #define	DDU_PACKAGE_OBJECT	"ddu_package_object"
 
+/* Pkg commands. */
+#define	PKG_PUBLISHER		"/usr/bin/pkg publisher"
+
 /* DDU error log */
 #define	DDU_ERRLOG		"/tmp/ddu_err.log"
 
+/*  DDU error module related. */
+#define	DDU_ERROR_MODULE		"DDU.ddu_errors"
+#define	DDU_PACKAGE_NOT_FOUND_EXC	"PackageNoFound"
+
 /* ICT module related definitions. */
 #define	ICT_MODULE		"osol_install.ict"
 #define	ICT_CLASS		"ICT"
 #define	ICT_UPDATE_ARCHIVE	"update_boot_archive"
 
 /* AI Manifest (AIM) related path definitions. */
-#define	AIM_PREFACE		    "auto_install/ai_instance/add_drivers/"
+#define	AIM_PREFACE		"auto_install/ai_instance/add_drivers/"
 #define	PKGSPEC_NODEPATH	"software"
 #define	ORIGIN_NODEPATH		"software/source/publisher/origin/name"
-#define	TYPE_NODEPATH \
-	"software[source/publisher/origin/name=\"%s\"]/software_data/type"
-#define	NAME_NODEPATH \
-	"software[source/publisher/origin/name=\"%s\":software_data/type=\"%s\"]/software_data/name"
+#define	TYPE_NODEPATH		"software[source/publisher/origin/" \
+				    "name=\"%s\"]/software_data/type"
+#define	NAME_NODEPATH		"software[source/publisher/origin/" \
+				    "name=\"%s\":software_data/" \
+				    "type=\"%s\"]/software_data/name"
 #define	ACTION_NONAME_NODEPATH \
-	"software[source/publisher/origin/name=\"%s\":software_data/type=\"%s\"]/software_data/action"
+				"software[source/publisher/origin/" \
+				    "name=\"%s\":software_data/" \
+				    "type=\"%s\"]/software_data/action"
 #define	ACTION_YESNAME_NODEPATH \
-	"software[source/publisher/origin/name=\"%s\":software_data/type=\"%s\":software_data/name=\"%s\"]/software_data/action"
+				"software[source/publisher/origin/" \
+				    "name=\"%s\":software_data/type=\"%s\":" \
+				    "software_data/name=\"%s\"]/" \
+				    "software_data/action"
 
 #define	SEARCH_NODEPATH		"search_all"
 #define	SEARCH_ORIGIN_NODEPATH	"search_all/source/publisher/origin/name"
@@ -72,6 +85,7 @@
 	PyThreadState *mainThreadState;
 	PyObject *pFunctionModule;
 	PyObject *pPackageModule;
+	PyObject *pErrorModule;
 	PyObject *pICTModule;
 } py_state_t;
 
@@ -83,31 +97,33 @@
 
 static py_state_t *auto_ddu_lib_init();
 static void auto_ddu_lib_fini(py_state_t *py_state_p);
+static void ai_dump_python_exception();
 static PyObject *ai_call_ddu_devscan(py_state_t *py_state_p,
     boolean_t get_only_missing_drivers, char *dev_type);
-static PyObject *ai_call_ddu_package_lookup(py_state_t *py_state_p,
-    PyObject *pDevObj, PyObject *pRepoList);
+static int ai_call_ddu_package_lookup(py_state_t *py_state_p,
+    PyObject *pDevObj, PyObject *pRepoList, PyObject **pPackageObj_p);
 static int ai_call_ddu_install_package(py_state_t *py_state_p,
     PyObject *ddu_package_obj, char *install_root, boolean_t third_party_ok);
 static PyObject *ai_new_ddu_package_object(py_state_t *py_state_p,
     char *type, char *name, char *origin);
 static int ai_get_ddu_package_object_values(PyObject *pDDUPackageObject,
-    char **type, char **origin, char **name, char **descr, char **inf_link,
+    char **type, char **location, char **name, char **descr, char **inf_link,
     boolean_t *third_party);
 static int ai_get_ddu_dev_data_values(PyObject *pDDUDevData,
-    char **dev_type, char **descr);
-static void ai_du_process_manual_pkg(py_state_t *py_state_p,
+    char **dev_type_p, char **descr_p, char **vendor_ID_p, char **device_ID_p,
+    char **class_p);
+static int ai_du_process_manual_pkg(py_state_t *py_state_p,
     PyObject *pPackageList, char *origin, char *type, char *name,
     char *noinstall);
-static void ai_du_process_manual_pkg_names(py_state_t *py_state_p,
-    PyObject *pPackageList, path_t *path_p, char *origin, char *type,
+static int ai_du_process_manual_pkg_names(py_state_t *py_state_p,
+    path_t *path_p, PyObject *pPackageList, char *origin, char *type,
     char *name);
-static void ai_du_process_manual_pkg_types(py_state_t *py_state_p,
+static int ai_du_process_manual_pkg_types(py_state_t *py_state_p,
     PyObject *pPackageList, path_t *path_p, char *origin, char *type);
-static PyObject *ai_du_get_manual_pkg_list(py_state_t *py_state_p,
-    path_t *path_p);
-static PyObject *ai_du_get_searched_pkg_list(py_state_t *py_state_p,
-    path_t *path_p);
+static int ai_du_get_manual_pkg_list(py_state_t *py_state_p, path_t *path_p,
+    PyObject **pPackageList_p);
+static int ai_du_get_searched_pkg_list(py_state_t *py_state_p, path_t *path_p,
+    char *install_root, PyObject **pPackageList_p);
 static int ai_du_install_packages(py_state_t *py_state_p,
     PyObject *pPkgTupleList, char *install_root, boolean_t honor_noinstall,
     int *num_installed_pkgs_p);
@@ -142,43 +158,70 @@
 static py_state_t *
 auto_ddu_lib_init()
 {
-	PyObject *pName;
 	py_state_t *py_state_p = malloc(sizeof (py_state_t));
 
-	py_state_p->pFunctionModule = NULL;
-	py_state_p->pPackageModule = NULL;
+	static PyObject *pFunctionModule = NULL;
+	static PyObject *pPackageModule = NULL;
+	static PyObject *pErrorModule = NULL;
+	static PyObject *pICTModule = NULL;
+
+	if (py_state_p == NULL) {
+		auto_debug_print(AUTO_DBGLVL_ERR, "auto_ddu_lib_init: "
+		    "No memory.\n");
+		return (NULL);
+	}
+
+	/* If one of the above is NULL, all will be NULL. */
+	if (pFunctionModule == NULL) {
+		PyObject *pName;
+
+		/* Get names of modules for use by python/C interfaces. */
+		if ((pName = PyString_FromString(DDU_FUNCTION_MODULE)) !=
+		    NULL) {
+			pFunctionModule = PyImport_Import(pName);
+			Py_DECREF(pName);
+		}
+		if ((pName = PyString_FromString(DDU_PACKAGE_MODULE)) != NULL) {
+			pPackageModule = PyImport_Import(pName);
+			Py_DECREF(pName);
+		}
+		if ((pName = PyString_FromString(DDU_ERROR_MODULE)) != NULL) {
+			pErrorModule = PyImport_Import(pName);
+			Py_DECREF(pName);
+		}
+		if ((pName = PyString_FromString(ICT_MODULE)) != NULL) {
+			pICTModule = PyImport_Import(pName);
+			Py_DECREF(pName);
+		}
+
+		/* Cleanup and return NULL on error. */
+		if ((pFunctionModule == NULL) || (pPackageModule == NULL) ||
+		    (pErrorModule == NULL) || (pICTModule == NULL)) {
+			auto_debug_print(AUTO_DBGLVL_ERR, "auto_ddu_lib_init: "
+			    "error accessing DDU library or ICT modules.\n");
+			PyErr_Print();
+			Py_XDECREF(pFunctionModule);
+			Py_XDECREF(pPackageModule);
+			Py_XDECREF(pErrorModule);
+			Py_XDECREF(pICTModule);
+			pFunctionModule = pPackageModule = NULL;
+			pErrorModule = pICTModule = NULL;
+			free(py_state_p);
+			return (NULL);
+		}
+	}
 
 	/* Set up python interpreter state. */
 	PyEval_InitThreads();
 	py_state_p->mainThreadState = PyThreadState_Get();
 	py_state_p->myThreadState =
 	    PyThreadState_New(py_state_p->mainThreadState->interp);
-	PyThreadState_Swap(py_state_p->myThreadState);
+	(void) PyThreadState_Swap(py_state_p->myThreadState);
 
-	/* Get names of modules for use by python/C interfaces. */
-	if ((pName = PyString_FromString(DDU_FUNCTION_MODULE)) != NULL) {
-		py_state_p->pFunctionModule = PyImport_Import(pName);
-		Py_DECREF(pName);
-	}
-	if ((pName = PyString_FromString(DDU_PACKAGE_MODULE)) != NULL) {
-		py_state_p->pPackageModule = PyImport_Import(pName);
-		Py_DECREF(pName);
-	}
-	if ((pName = PyString_FromString(ICT_MODULE)) != NULL) {
-		py_state_p->pICTModule = PyImport_Import(pName);
-		Py_DECREF(pName);
-	}
-
-	/* Cleanup and return NULL on error. */
-	if ((py_state_p->pFunctionModule == NULL) ||
-	    (py_state_p->pPackageModule == NULL) ||
-	    (py_state_p->pICTModule == NULL)) {
-		auto_debug_print(AUTO_DBGLVL_ERR, "auto_ddu_lib_init: "
-		    "error accessing DDU library or ICT modules.\n");
-		PyErr_Print();
-		auto_ddu_lib_fini(py_state_p);
-		py_state_p = NULL;
-	}
+	py_state_p->pFunctionModule = pFunctionModule;
+	py_state_p->pPackageModule = pPackageModule;
+	py_state_p->pErrorModule = pErrorModule;
+	py_state_p->pICTModule = pICTModule;
 
 	return (py_state_p);
 }
@@ -198,16 +241,49 @@
 	if (py_state_p == NULL) {
 		return;
 	}
-	Py_XDECREF(py_state_p->pFunctionModule);
-	Py_XDECREF(py_state_p->pPackageModule);
-	Py_XDECREF(py_state_p->pICTModule);
-	PyThreadState_Swap(py_state_p->mainThreadState);
+	(void) PyThreadState_Swap(py_state_p->mainThreadState);
 	PyThreadState_Clear(py_state_p->myThreadState);
 	PyThreadState_Delete(py_state_p->myThreadState);
 	free(py_state_p);
 }
 
 /*
+ * ai_dump_python_exception:
+ * Dump the class and message of a python exception.  Traceback not dumped.
+ *
+ * Caveat: An exception must be ready to be dumped, as indicated by
+ * PyErr_Occurred() * returning Non-NULL.
+ *
+ * Arguments: None
+ *
+ * Returns: N/A
+ */
+static void
+ai_dump_python_exception()
+{
+	PyObject *pType, *pValue, *pTraceback;
+	PyObject *pTypeString, *pValueString;
+
+	if (PyErr_Occurred() == NULL) {
+		return;
+	}
+
+	PyErr_Fetch(&pType, &pValue, &pTraceback);
+	pTypeString = PyObject_Str(pType);
+	pValueString = PyObject_Str(pValue);
+	auto_debug_print(AUTO_DBGLVL_ERR,
+	    "%s\n", PyString_AsString(pTypeString));
+	auto_debug_print(AUTO_DBGLVL_ERR,
+	    "%s\n", PyString_AsString(pValueString));
+	Py_DECREF(pType);
+	Py_DECREF(pValue);
+	Py_DECREF(pTraceback);
+	Py_DECREF(pTypeString);
+	Py_DECREF(pValueString);
+	PyErr_Clear();
+}
+
+/*
  * ai_call_ddu_build_repo_list:
  * Call the DDU library ddu_build_repo_list function.  This sets up the
  * list of repositories specified (as name/URL tuples) in the second argument,
@@ -244,17 +320,16 @@
 		Py_INCREF(pRepoTupleList);
 
 		/* Set up args to python function and call it. */
-		PyTuple_SetItem(pArgs, 0, pRepoTupleList);
+		(void) PyTuple_SetItem(pArgs, 0, pRepoTupleList);
 		pRet = PyObject_CallObject(pFunc, pArgs);
 		Py_DECREF(pArgs);
 
-		if ((PyErr_Occurred()) || (pRet == NULL) || (pRet == Py_None)) {
+		if ((PyErr_Occurred() != NULL) || (pRet == NULL) ||
+		    (pRet == Py_None)) {
 			auto_debug_dump_file(AUTO_DBGLVL_ERR, DDU_ERRLOG);
 			auto_debug_print(AUTO_DBGLVL_ERR,
 			    "%s returned an error.\n", DDU_BUILD_REPO_LIST);
-			if (PyErr_Occurred()) {
-				PyErr_Print();
-			}
+			ai_dump_python_exception();
 			Py_XDECREF(pRet);
 			pRet = NULL;
 		}
@@ -279,7 +354,8 @@
  *
  * Returns:
  *   Success:
- *	A python object representing a list of ddu_dev_data objects is returned.
+ *	A python object representing a list of unique ddu_dev_data objects is
+ *	returned.
  *	- NOTE: if no devices are missing drivers and get_only_missing_drivers
  *	  is true, then an empty list is returned.
  *	- A ddu_dev_data object represents a found device.
@@ -291,6 +367,11 @@
     boolean_t get_only_missing_drivers, char *dev_type)
 {
 	PyObject *pRet = NULL;
+	PyObject *pList = NULL;
+	Py_ssize_t orig_listlen;
+	char **vids, **dids, **classes;
+	Py_ssize_t new_listused = 0;
+	Py_ssize_t i, j;
 
 	/* Find the function */
 	PyObject *pFunc = PyObject_GetAttrString(py_state_p->pFunctionModule,
@@ -299,28 +380,84 @@
 	if ((pFunc == NULL) || (!PyCallable_Check(pFunc))) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "Function not callable: %s\n", DDU_DEVSCAN);
+		Py_XDECREF(pFunc);
+		return (NULL);
 	} else {
 		/* Set up args to python function and call it. */
 		PyObject *pArgs = PyTuple_New(2);
-		PyTuple_SetItem(pArgs, 0,
+		(void) PyTuple_SetItem(pArgs, 0,
 		    PyBool_FromLong((long)get_only_missing_drivers));
-		PyTuple_SetItem(pArgs, 1, PyString_FromString(dev_type));
-		pRet = PyObject_CallObject(pFunc, pArgs);
+		(void) PyTuple_SetItem(pArgs, 1, PyString_FromString(dev_type));
+		pList = PyObject_CallObject(pFunc, pArgs);
 
 		Py_DECREF(pArgs);
-		if ((PyErr_Occurred()) || (pRet == NULL) || (pRet == Py_None)) {
+		if ((PyErr_Occurred() != NULL) || (pList == NULL) ||
+		    (pList == Py_None)) {
 			auto_debug_dump_file(AUTO_DBGLVL_ERR, DDU_ERRLOG);
 			auto_debug_print(AUTO_DBGLVL_ERR,
 			    "%s returned an error.\n", DDU_DEVSCAN);
-			if (PyErr_Occurred()) {
-				PyErr_Print();
-			}
-			Py_XDECREF(pRet);
-			pRet = NULL;
+			ai_dump_python_exception();
+			Py_XDECREF(pList);
+			Py_XDECREF(pFunc);
+			return (NULL);
 		}
 	}
 
 	Py_XDECREF(pFunc);
+
+	orig_listlen = PyList_Size(pList);
+	if (orig_listlen < 2) {
+		return (pList);
+	}
+
+	/* Check for duplicates. */
+	vids = (char **)malloc(sizeof (char *) * orig_listlen);
+	dids = (char **)malloc(sizeof (char *) * orig_listlen);
+	classes = (char **)malloc(sizeof (char *) * orig_listlen);
+	if ((vids == NULL) || (dids == NULL) || (classes == NULL)) {
+		auto_debug_print(AUTO_DBGLVL_ERR,
+		    "ai_call_ddu_devscan: No memory.\n");
+		return (NULL);
+	}
+
+	/* Build a list of unique values to be returned. */
+	pRet = PyList_New(0);
+
+	/* Loop through the list. */
+	for (i = 0; i < orig_listlen; i++) {
+		PyObject *pDDUDevData = PyList_GetItem(pList, i);
+		char *vendor_ID, *device_ID, *class;
+		boolean_t dup;
+
+		if (ai_get_ddu_dev_data_values(pDDUDevData, NULL, NULL,
+		    &vendor_ID, &device_ID, &class) != AUTO_INSTALL_SUCCESS) {
+			/* If can't compare, just allow it. */
+			continue;
+		}
+
+		/* Check for matching vendor, device, class. */
+		for (j = 0, dup = B_FALSE; j < new_listused; j++) {
+			if ((strcmp(class, classes[j]) == 0) &&
+			    (strcmp(device_ID, dids[j]) == 0) &&
+			    (strcmp(vendor_ID, vids[j]) == 0)) {
+				dup = B_TRUE;
+				break;
+			}
+		}
+
+		if (!dup) {
+			(void) PyList_Append(pRet, pDDUDevData);
+			vids[new_listused] = vendor_ID;
+			dids[new_listused] = device_ID;
+			classes[new_listused++] = class;
+		}
+	}
+
+	free(vids);
+	free(dids);
+	free(classes);
+
+	Py_XDECREF(pList);
 	return (pRet);
 }
 
@@ -335,22 +472,28 @@
  *   pDevObj: A python ddu_dev_data object representing a device.
  *   pRepoList: A python list of ddu_repo_object objects.  This represents the
  *	list of repositories to search through for a driver package.
+ *   pPackageObj_p: Pointer to the returned ddu_package_object.
  *
  * Returns:
- *   Success: A python ddu_package_object representing a package to install for
- *	the given device.
- *   Failure: NULL
+ *   AUTO_INSTALL_SUCCESS: pPackageObj_p points to an object representing a
+ *	package to install for the given device.
+ *   AUTO_INSTALL_PKG_NOT_FOUND: No package was found to install for the given
+ *	device.  pPackageObj_p set to NULL.
+ *   AUTO_INSTALL_FAILURE: Corresponds to an error other than not finding the
+ *	package to install for the given device.  pPackageObj_p set to NULL.
  */
-static PyObject *
+static int
 ai_call_ddu_package_lookup(py_state_t *py_state_p,
-    PyObject *pDevObj, PyObject *pRepoList)
+    PyObject *pDevObj, PyObject *pRepoList, PyObject **pPackageObj_p)
 {
-	PyObject *pRet = NULL;
+	int err = AUTO_INSTALL_SUCCESS;
 
 	/* Find the function */
 	PyObject *pFunc = PyObject_GetAttrString(py_state_p->pFunctionModule,
 	    DDU_PACKAGE_LOOKUP);
 
+	*pPackageObj_p = NULL;
+
 	if ((pFunc == NULL) || (!PyCallable_Check(pFunc))) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "Function not callable: %s\n", DDU_PACKAGE_LOOKUP);
@@ -359,26 +502,61 @@
 		PyObject *pArgs = PyTuple_New(2);
 		Py_INCREF(pDevObj);	/* PyTuple_SetItem steals reference. */
 		Py_INCREF(pRepoList);	/* PyTuple_SetItem steals reference. */
-		PyTuple_SetItem(pArgs, 0, pDevObj);
-		PyTuple_SetItem(pArgs, 1, pRepoList);
+		(void) PyTuple_SetItem(pArgs, 0, pDevObj);
+		(void) PyTuple_SetItem(pArgs, 1, pRepoList);
 
 		/* Call ddu_package_lookup() */
-		pRet = PyObject_CallObject(pFunc, pArgs);
+		*pPackageObj_p = PyObject_CallObject(pFunc, pArgs);
 		Py_DECREF(pArgs);
-		if ((PyErr_Occurred()) || (pRet == NULL) || (pRet == Py_None)) {
+		if ((PyErr_Occurred() != NULL) || (*pPackageObj_p == NULL) ||
+		    (*pPackageObj_p == Py_None)) {
+			err = AUTO_INSTALL_FAILURE;
 			auto_debug_dump_file(AUTO_DBGLVL_ERR, DDU_ERRLOG);
 			auto_debug_print(AUTO_DBGLVL_ERR,
 			    "%s returned an error.\n", DDU_PACKAGE_LOOKUP);
-			if (PyErr_Occurred()) {
-				PyErr_Print();
+			if (PyErr_Occurred() != NULL) {
+				PyObject *pType, *pValue, *pTraceback;
+				PyObject *pPkgNotFndExcObj =
+				    PyObject_GetAttrString(
+				    py_state_p->pErrorModule,
+				    DDU_PACKAGE_NOT_FOUND_EXC);
+				PyErr_Fetch(&pType, &pValue, &pTraceback);
+
+				if (PyObject_IsSubclass(pType,
+				    pPkgNotFndExcObj) == 1) {	/* 1 = match */
+					err = AUTO_INSTALL_PKG_NOT_FND;
+				}
+				Py_DECREF(pType);
+				Py_DECREF(pValue);
+				Py_DECREF(pTraceback);
+				Py_DECREF(pPkgNotFndExcObj);
+				PyErr_Clear();
 			}
-			Py_XDECREF(pRet);
-			pRet = NULL;
+			Py_XDECREF(*pPackageObj_p);
+			*pPackageObj_p = NULL;
+
+		} else {
+			/*
+			 * DDU can return a pPackageObj_p that has type unknown,
+			 * no location and no inf_link.  Treat these as
+			 * "package not found" as well.
+			 */
+			char *ttype = empty_string;
+			char *tlocn = empty_string;
+			char *tinf_link = empty_string;
+			(void) ai_get_ddu_package_object_values(*pPackageObj_p,
+			    &ttype, &tlocn, NULL, NULL, &tinf_link, NULL);
+			if ((tlocn[0] == '\0') && (tinf_link[0] == '\0') &&
+			    (strcmp(ttype, "UNK") == 0)) {
+				err = AUTO_INSTALL_PKG_NOT_FND;
+				Py_XDECREF(*pPackageObj_p);
+				*pPackageObj_p = NULL;
+			}
 		}
 	}
 
 	Py_XDECREF(pFunc);
-	return (pRet);
+	return (err);
 }
 
 /*
@@ -423,20 +601,21 @@
 		/* Set up args to python function. */
 		PyObject *pArgs = PyTuple_New(3);
 		Py_INCREF(pDDUPackageObj);	/* PyTuple_SetItem steals ref */
-		PyTuple_SetItem(pArgs, 0, pDDUPackageObj);
-		PyTuple_SetItem(pArgs, 1, PyString_FromString(install_root));
-		PyTuple_SetItem(pArgs, 2,
+		(void) PyTuple_SetItem(pArgs, 0, pDDUPackageObj);
+		(void) PyTuple_SetItem(pArgs, 1,
+		    PyString_FromString(install_root));
+		(void) PyTuple_SetItem(pArgs, 2,
 		    PyBool_FromLong((long)third_party_ok));
 
 		/* Call ddu_install_packages() */
-		PyObject_CallObject(pFunc, pArgs);
+		(void) PyObject_CallObject(pFunc, pArgs);
 		Py_DECREF(pArgs);
 
-		if (PyErr_Occurred()) {
+		if (PyErr_Occurred() != NULL) {
 			auto_debug_dump_file(AUTO_DBGLVL_ERR, DDU_ERRLOG);
 			auto_debug_print(AUTO_DBGLVL_ERR,
 			    "%s returned an error\n", DDU_INSTALL_PACKAGE);
-			PyErr_Print();
+			ai_dump_python_exception();
 			rval = AUTO_INSTALL_FAILURE;
 		}
 	}
@@ -447,7 +626,7 @@
 
 /*
  * ai_new_ddu_package_object:
- * Create a new ddu_package_object of given type, name and origin.
+ * Create a new ddu_package_object of given type, name and location.
  *
  * Arguments:
  *   py_state_p: Initialized py_state_t object.
@@ -457,7 +636,7 @@
  *
  * Returns:
  *   Success: A new python ddu_package_object object of the given
- *	type/name/origin.
+ *	type/name/location.
  *   Failure: NULL
  */
 static PyObject *
@@ -483,20 +662,19 @@
 	} else {
 		/* Set up args to python function. */
 		PyObject *pArgs = PyTuple_New(3);
-		PyTuple_SetItem(pArgs, 0, PyString_FromString(type));
-		PyTuple_SetItem(pArgs, 1, PyString_FromString(name));
-		PyTuple_SetItem(pArgs, 2, PyString_FromString(origin));
+		(void) PyTuple_SetItem(pArgs, 0, PyString_FromString(type));
+		(void) PyTuple_SetItem(pArgs, 1, PyString_FromString(name));
+		(void) PyTuple_SetItem(pArgs, 2, PyString_FromString(origin));
 
 		/* Call ddu_package_object constructor. */
 		pRet = PyObject_CallObject(pFunc, pArgs);
 		Py_DECREF(pArgs);
-		if ((PyErr_Occurred()) || (pRet == NULL) || (pRet == Py_None)) {
+		if ((PyErr_Occurred() != NULL) || (pRet == NULL) ||
+		    (pRet == Py_None)) {
 			auto_debug_dump_file(AUTO_DBGLVL_ERR, DDU_ERRLOG);
 			auto_debug_print(AUTO_DBGLVL_ERR,
 			    "ddu_package_object constructor failed\n");
-			if (PyErr_Occurred()) {
-				PyErr_Print();
-			}
+			ai_dump_python_exception();
 			Py_XDECREF(pRet);
 			pRet = NULL;
 		}
@@ -520,7 +698,7 @@
  *	ddu_package_object;  not verified.
  *   type: char string pointer returned filled in with "pkg_type" field.
  *	Not processed if NULL.
- *   origin: char string pointer returned filled in with "pkg_location" field.
+ *   location: char string pointer returned filled in with "pkg_location" field.
  *	Not processed if NULL.
  *   name: char string pointer returned filled in with "pkg_name" field.
  *	Not processed if NULL.
@@ -538,7 +716,7 @@
  */
 static int
 ai_get_ddu_package_object_values(PyObject *pDDUPackageObject,
-    char **type, char **origin, char **name, char **descr, char **inf_link,
+    char **type, char **location, char **name, char **descr, char **inf_link,
     boolean_t *third_party)
 {
 	PyObject *pValue;
@@ -554,7 +732,7 @@
 		*type = PyString_AsString(pValue);
 	}
 
-	if (origin != NULL) {
+	if (location != NULL) {
 		pValue = PyObject_GetAttrString(pDDUPackageObject,
 		    "pkg_location");
 		if (pValue == NULL) {
@@ -563,7 +741,7 @@
 			    "no ddu_package_object pkg_location field.\n");
 			return (AUTO_INSTALL_FAILURE);
 		}
-		*origin = PyString_AsString(pValue);
+		*location = PyString_AsString(pValue);
 	}
 
 	if (name != NULL) {
@@ -628,9 +806,15 @@
  * Arguments:
  *   pDDUDevData: Object to extract values from.  Assumed to be a
  *	ddu_dev_data object;  not verified.
- *   dev_type: char string pointer returned filled in with "device_type" field.
+ *   dev_type_p: char string pointer returned filled in with "device_type"
+ *	field.  Not processed if NULL.
+ *   descr_p: char string pointer returned filled in with "description" field.
  *	Not processed if NULL.
- *   descr: char string pointer returned filled in with "description" field.
+ *   vendor_ID_p: char string pointer returned filled in with "vendor ID" field.
+ *	Not processed if NULL.
+ *   device_ID_p: char string pointer returned filled in with "device ID" field.
+ *	Not processed if NULL.
+ *   class_p: char string pointer returned filled in with PCI "class" field.
  *	Not processed if NULL.
  *
  * Returns:
@@ -639,11 +823,12 @@
  *	extracted.
  */
 static int
-ai_get_ddu_dev_data_values(PyObject *pDDUDevData, char **dev_type, char **descr)
+ai_get_ddu_dev_data_values(PyObject *pDDUDevData, char **dev_type_p,
+    char **descr_p, char **vendor_ID_p, char **device_ID_p, char **class_p)
 {
 	PyObject *pValue;
 
-	if (dev_type != NULL) {
+	if (dev_type_p != NULL) {
 		pValue = PyObject_GetAttrString(pDDUDevData, "device_type");
 		if (pValue == NULL) {
 			auto_debug_print(AUTO_DBGLVL_ERR,
@@ -651,10 +836,10 @@
 			    "no ddu_dev_data device_type field.\n");
 			return (AUTO_INSTALL_FAILURE);
 		}
-		*dev_type = PyString_AsString(pValue);
+		*dev_type_p = PyString_AsString(pValue);
 	}
 
-	if (descr != NULL) {
+	if (descr_p != NULL) {
 		pValue = PyObject_GetAttrString(pDDUDevData, "description");
 		if (pValue == NULL) {
 			auto_debug_print(AUTO_DBGLVL_ERR,
@@ -662,7 +847,40 @@
 			    "no ddu_dev_data description field.\n");
 			return (AUTO_INSTALL_FAILURE);
 		}
-		*descr = PyString_AsString(pValue);
+		*descr_p = PyString_AsString(pValue);
+	}
+
+	if (vendor_ID_p != NULL) {
+		pValue = PyObject_GetAttrString(pDDUDevData, "vendor_id");
+		if (pValue == NULL) {
+			auto_debug_print(AUTO_DBGLVL_ERR,
+			    "ai_get_ddu_dev_data_values: "
+			    "no ddu_dev_data vendor_id field.\n");
+			return (AUTO_INSTALL_FAILURE);
+		}
+		*vendor_ID_p = PyString_AsString(pValue);
+	}
+
+	if (device_ID_p != NULL) {
+		pValue = PyObject_GetAttrString(pDDUDevData, "device_id");
+		if (pValue == NULL) {
+			auto_debug_print(AUTO_DBGLVL_ERR,
+			    "ai_get_ddu_dev_data_values: "
+			    "no ddu_dev_data device_id field.\n");
+			return (AUTO_INSTALL_FAILURE);
+		}
+		*device_ID_p = PyString_AsString(pValue);
+	}
+
+	if (class_p != NULL) {
+		pValue = PyObject_GetAttrString(pDDUDevData, "class_code");
+		if (pValue == NULL) {
+			auto_debug_print(AUTO_DBGLVL_ERR,
+			    "ai_get_ddu_dev_data_values: "
+			    "no ddu_dev_data class_code field.\n");
+			return (AUTO_INSTALL_FAILURE);
+		}
+		*class_p = PyString_AsString(pValue);
 	}
 
 	return (AUTO_INSTALL_SUCCESS);
@@ -675,24 +893,29 @@
  * Arguments:
  *   py_state_p: Initialized py_state_t object.
  *   pPackageList: List of packages to append the new ddu_package_object to.
- *   origin: directory of where package is located.
+ *   origin: directory of where package or package directive is located.
  *   type: type of package.
  *   name: name of package.
  *   noinstall: boolean whether package is to be installed only to booted
  *	environment, not to target.
  *
- * Returns: None
- *   Note 1: the pPackageList will be modified.
- *   Note 2: Appropriate error messages are logged/displayed.
+ * Returns:
+ *   AUTO_INSTALL_SUCCESS: A new package object was successfully appended to
+ *	pPackageList.
+ *   AUTO_INSTALL_FAILURE: An error occurred when trying to create a new
+ *	package object or append it to the pPackageList.
+ *
+ *   Note: The list object referenced by pPackageList will be modified.
  */
-static void
+static int
 ai_du_process_manual_pkg(py_state_t *py_state_p, PyObject *pPackageList,
     char *origin, char *type, char *name, char *noinstall)
 {
 	PyObject *pDDUPackageObject;
 	PyObject *pTuple;
 
-	auto_log_print(gettext("Found manifest entry for package:\n"));
+	auto_log_print(gettext(
+	    "Add Drivers: Found manifest entry for package:\n"));
 	if (name != empty_string) {
 		auto_log_print(gettext("  type:%s, origin:%s, name:%s\n"),
 		    type, origin, name);
@@ -714,48 +937,55 @@
 
 	if (pDDUPackageObject == NULL) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
-		    "ai_du_get_pkg_list: <add_drivers> error:\n"
+		    "ai_du_process_manual_pkg: <add_drivers> error:\n"
 		    "Error creating new package object for "
 		    "origin %s %s\n", origin, name);
-		return;
+		return (AUTO_INSTALL_FAILURE);
 	}
 
 	pTuple = PyTuple_New(3);
-	PyTuple_SetItem(pTuple, 0, pDDUPackageObject);
-	PyTuple_SetItem(pTuple, 1, Py_True);	/* third party OK */
-	PyTuple_SetItem(pTuple, 2,
+	(void) PyTuple_SetItem(pTuple, 0, pDDUPackageObject);
+	(void) PyTuple_SetItem(pTuple, 1, Py_True);	/* third party OK */
+	(void) PyTuple_SetItem(pTuple, 2,
 	    (strcmp(noinstall, "true") == 0) ? Py_True : Py_False);
 
 	/*
 	 * NOTE: Don't decref pTuple here as PyList_Append doesn't
 	 * steal a reference to it.
 	 */
-	PyList_Append(pPackageList, pTuple);
+	(void) PyList_Append(pPackageList, pTuple);
+	return (AUTO_INSTALL_SUCCESS);
 }
 
 /*
  * ai_du_process_manual_pkg_names:
- * Do any processing of packages for which unique origin, type and name are
- *	known.
+ * Do any processing of packages for which unique origin (location), type and
+ *	name are known.
  *
  * Arguments:
  *   py_state_p: Initialized py_state_t object.
+ *   path_p: Used to build nodepath strings for manifest checking.
  *   pPackageList: List of packages to append the new ddu_package_object to.
  *   origin: directory of where package is located.
  *   type: type of package.
  *   name: name of package.
  *
- * Returns: None
- *   Note 1: the pPackageList will be modified.
- *   Note 2: Appropriate error messages are logged/displayed.
+ * Returns:
+ *   AUTO_INSTALL_SUCCESS: Package processed successfully and appended to
+ *	pPackageList.
+ *   AUTO_INSTALL_FAILURE: An error occurred.  No package appended to
+ *	pPackageList.
+ *
+ *   Note 1: the object pointed to by pPackageList will be modified.
  */
-static void
-ai_du_process_manual_pkg_names(py_state_t *py_state_p, PyObject *pPackageList,
-    path_t *path_p, char *origin, char *type, char *name)
+static int
+ai_du_process_manual_pkg_names(py_state_t *py_state_p, path_t *path_p,
+    PyObject *pPackageList, char *origin, char *type, char *name)
 {
 	char **actions;
 	int actions_len;
 	char *nodespec;
+	int rval;
 
 	/* Get the action attribute. */
 
@@ -768,32 +998,33 @@
 
 	if (snprintf(path_p->post_prefix_start, path_p->post_prefix_len,
 	    nodespec, origin, type, name) >= path_p->post_prefix_len) {
-		auto_debug_print(AUTO_DBGLVL_ERR, "ai_du_get_pkg_list: "
+		auto_debug_print(AUTO_DBGLVL_ERR,
+		    "ai_du_process_manual_pkg_names: "
 		    "<add_drivers> manifest error:\n"
 		    "action path buffer overflow for origin \"%s\", "
 		    "type \"%s\", name \"%s\"\n", origin, type, name);
-		return;
+		return (AUTO_INSTALL_FAILURE);
 	}
 
 	actions = ai_get_manifest_values(path_p->path_str, &actions_len);
 
 	/*
-	 * Note: action must be present and must be either "install"
-	 * or "noinstall".
+	 * Note: action must be present and must be
+	 * either "install" or "noinstall".
 	 */
 	if (actions_len <= 0) {
-		auto_log_print(gettext("ai_du_get_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "<add_drivers> manifest error:\n"
 		    "no action value for origin \"%s\", "
 		    "type \"%s\", name \"%s\"\n"), origin, type, name);
-		return;
+		rval = AUTO_INSTALL_FAILURE;
 
 	} else if (actions_len > 1) {
-		auto_log_print(gettext("ai_du_get_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "<add_drivers> manifest error:\n"
 		    "multiple action values for origin \"%s\", "
 		    "type \"%s\", name \"%s\"\n"), origin, type, name);
-		return;
+		rval = AUTO_INSTALL_FAILURE;
 
 	} else if (strcmp(actions[0], "install") == 0) {
 		/*
@@ -803,8 +1034,8 @@
 		 */
 
 		/* Obj pointed to by pPackageList will be modified. */
-		ai_du_process_manual_pkg(py_state_p, pPackageList, origin,
-		    type, name, empty_string);
+		rval = ai_du_process_manual_pkg(py_state_p, pPackageList,
+		    origin, type, name, empty_string);
 	} else if (strcmp(actions[0], "noinstall") == 0) {
 		/*
 		 * If action="noinstall" then call ai_du_process_manual_pkg with
@@ -812,22 +1043,22 @@
 		 * installed in both boot env and not in target.
 		 */
 		/* Obj pointed to by pPackageList will be modified. */
-		ai_du_process_manual_pkg(py_state_p, pPackageList, origin,
-		    type, name, "true");
+		rval = ai_du_process_manual_pkg(py_state_p, pPackageList,
+		    origin, type, name, "true");
 	} else {
-		auto_log_print(gettext("ai_du_get_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "<add_drivers> manifest error:\n"
 		    "action must be install or noinstall for origin \"%s\", "
 		    "type \"%s\", name \"%s\"\n"), origin, type, name);
-		return;
-
+		rval = AUTO_INSTALL_FAILURE;
 	}
 	ai_free_manifest_values(actions);
+	return (rval);
 }
 
 /*
  * ai_du_process_manual_pkg_types:
- * Do any processing of packages for which unique origin and type are known.
+ * Do any processing of packages for which unique location and type are known.
  *
  * Arguments:
  *   py_state_p: Initialized py_state_t object.
@@ -835,11 +1066,16 @@
  *   origin: directory of where package is located.
  *   type: type of package.
  *
- * Returns: None
+ * Returns:
+ *   AUTO_INSTALL_SUCCESS: Package processed successfully and appended to
+ *	pPackageList.
+ *   AUTO_INSTALL_FAILURE: An error occurred.  No package appended to
+ *	pPackageList.
+ *
  *   Note 1: the pPackageList will be modified.
  *   Note 2: Appropriate error messages are logged/displayed.
  */
-static void
+static int
 ai_du_process_manual_pkg_types(py_state_t *py_state_p, PyObject *pPackageList,
     path_t *path_p, char *origin, char *type)
 {
@@ -847,26 +1083,27 @@
 	char **uniq_names;
 	int namelen;
 	int k;
+	int rval = AUTO_INSTALL_SUCCESS;
 
 	if ((strcmp(type, "P5I") != 0) &&
 	    (strcmp(type, "SVR4") != 0) &&
 	    (strcmp(type, "DU") != 0)) {
-		auto_log_print(gettext("ai_du_get_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "<add_drivers> manifest error:\n"
-		    "invalid type %s given for origin %s\n"),
-		    type, origin);
-		return;
+		    "invalid type %s given for origin %s\n"), type, origin);
+		return (AUTO_INSTALL_FAILURE);
 	}
 
 	/* Get all names assocated with type and origin. */
 
 	if (snprintf(path_p->post_prefix_start, path_p->post_prefix_len,
 	    NAME_NODEPATH, origin, type) >= path_p->post_prefix_len) {
-		auto_debug_print(AUTO_DBGLVL_ERR, "ai_du_get_pkg_list: "
+		auto_debug_print(AUTO_DBGLVL_ERR,
+		    "ai_du_process_manual_pkg_types: "
 		    "<add_drivers> manifest error:\n"
 		    "name path buffer overflow for origin "
 		    "%s, type %s\n", origin, type);
-		return;
+		return (AUTO_INSTALL_FAILURE);
 	}
 
 	names = ai_get_manifest_values(path_p->path_str, &namelen);
@@ -878,54 +1115,54 @@
 	if (strcmp(type, "SVR4") != 0) {
 		if (namelen > 0) {
 			auto_log_print(gettext(
-			    "ai_du_get_pkg_list: <add_drivers> "
+			    "Add Drivers: <add_drivers> "
 			    "manifest error:\n"
-			    "name given to P5I or DU pkg spec at "
+			    "name given to P5I or DU package specification at "
 			    "origin %s\n"), origin);
-			return;
+			rval = AUTO_INSTALL_FAILURE;
 		} else {
 			/* Obj pointed to by pPackageList will be modified. */
-			ai_du_process_manual_pkg_names(py_state_p, pPackageList,
-			    path_p, origin, type, empty_string);
+			rval = ai_du_process_manual_pkg_names(py_state_p,
+			    path_p, pPackageList, origin, type, empty_string);
 		}
 
-	/*
-	 * There must be at least one "name" entry per pkg spec
-	 * for SVR4 type.
-	 */
+	/* There must be at least one "name" entry per pkgspec for SVR4 type. */
 	} else if (namelen <= 0) {
-		auto_log_print(gettext("ai_du_get_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "<add_drivers> manifest error:\n"
-		    "no name given for SVR4 pkg spec at origin %s, type %s\n"),
-		    origin, type);
-		return;
+		    "  no name given for SVR4 package specification\n"
+		    "  at origin %s, type %s\n"), origin, type);
+		rval = AUTO_INSTALL_FAILURE;
 
 	} else {
 		/* Process each origin/type/name entry. */
 		for (k = 0; k < namelen; k++) {
 
 			/* Obj pointed to by pPackageList will be modified. */
-			ai_du_process_manual_pkg_names(py_state_p, pPackageList,
-			    path_p, origin, type, names[k]);
+			int status = ai_du_process_manual_pkg_names(py_state_p,
+			    path_p, pPackageList, origin, type, names[k]);
+			if (status == AUTO_INSTALL_FAILURE) {
+				rval = AUTO_INSTALL_FAILURE;
+			}
 		}
-
 	}
 	ai_free_manifest_values(names);
+	return (rval);
 }
 
 /*
  * ai_du_get_manual_pkg_list:
- * Read the AI ai.xml Manifest file and process the <software> under the
- * <add_drivers> section.  A <software> is a manual specification of a package
- * to install.  Do error checking of the manifest as necessary, as this function
- * reads the manifest before it is validated against a schema.
+ * Read the AI ai.xml Manifest file and process the <software> tags under the
+ * <add_drivers> section.  <software> represents a manual specification of a
+ * package to install.  Do error checking of the manifest as necessary, as this
+ * function reads the manifest before it is validated against a schema.
  *
  * Validates syntax and processes the following from the manifest:
  *	<add_drivers>
  *		<software>
  *			<source>
  *				<publisher>
- *					<origin name="origin"/>
+ *					<origin name="location"/>
  *				</publisher>
  *			</source>
  *			<software_data type="type" action="noinstall">
@@ -937,70 +1174,84 @@
  *	type can be "SVR4", "P5I" or "DU".
  *	name not allowed if type is "P5I" or "DU"
  *
+ * Always return a list.  An empty list can be returned if the manifest shows
+ * there are no packages to install for Driver Update, or on some errors.
+ *
  * Arguments:
  *   py_state_p: Initialized py_state_t object.
  *   path_p: Used to build nodepath strings for manifest checking.
  *
  * Returns:
- *   Success: A python list of (ddu_package_object, third_party_ok, noinstall)
- *	tuples suitable for input to ai_du_install_packages().
- *	NOTE: if the manifest shows no packages to install for Driver Update,
- *	this function will return an empty list.
- *   Failure: NULL
+ *   AUTO_INSTALL_SUCCESS: A complete python list of (ddu_package_object,
+ *	third_party_ok, noinstall) tuples suitable for input to
+ *	ai_du_install_packages() has been created.
+ *   AUTO_INSTALL_FAILURE: A python list of tuples suitable for input to
+ *	ai_du_install_packages() has been created, but is missing one or more
+ *	requested packages due to errors.  These errors could be manifest
+ *	parsing errors or errors in setting up the packages.
  *
  * NOTE: check installer logfile for details of the failure.
  */
-static PyObject *
-ai_du_get_manual_pkg_list(py_state_t *py_state_p, path_t *path_p)
+static int
+ai_du_get_manual_pkg_list(py_state_t *py_state_p, path_t *path_p,
+    PyObject **pPackageList_p)
 {
-	PyObject *pPackageList = NULL;
 	char **uniq_origins = NULL;
 	char **types = NULL;
 	int origin_len, typelen;
 	char **origins;
 	char **uniq_types;
-	int num_pkg_specs;
+	int num_pkgspecs;
 	int i, j;
+	int rval = AUTO_INSTALL_SUCCESS;
+
+	/*
+	 * Initialize a zero-length list.
+	 * This will be returned empty if nothing to install has been found
+	 * or if an error is found early on.
+	 */
+	*pPackageList_p = PyList_New(0);
 
 	/* Read manifest for specific package requests. */
 
-	/* Get the number of pkg spec entries. */
+	/* Get the number of <software> package spec entries. */
 	if (strlcpy(path_p->post_prefix_start, PKGSPEC_NODEPATH,
 	    path_p->post_prefix_len) > path_p->post_prefix_len) {
-		auto_debug_print(AUTO_DBGLVL_ERR,
-		    "ai_du_get_pkg_list: pkg spec path buffer overflow\n");
-		return (NULL);
+		auto_debug_print(AUTO_DBGLVL_ERR, "ai_du_get_manual_pkg_list: "
+		    "<software> path buffer overflow\n");
+		return (AUTO_INSTALL_FAILURE);
 	}
 
-	/* Use "origins" like a dummy here.  Interest only in num_pkg_specs. */
-	origins = ai_get_manifest_values(path_p->path_str, &num_pkg_specs);
+	/* Use "origins" like a dummy here.  Interest only in num_pkgspecs. */
+	origins = ai_get_manifest_values(path_p->path_str, &num_pkgspecs);
 	ai_free_manifest_values(origins);
 
-	/* No pkg specs.  Return an empty list. */
-	if (num_pkg_specs <= 0) {
-		return (PyList_New(0));
+	/* No package specs.  Return an empty list. */
+	if (num_pkgspecs <= 0) {
+		return (AUTO_INSTALL_SUCCESS);
 	}
 
 	/* Retrieve a list of all specific package request origins. */
 	if (strlcpy(path_p->post_prefix_start, ORIGIN_NODEPATH,
 	    path_p->post_prefix_len) > path_p->post_prefix_len) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
-		    "ai_du_get_pkg_list: origin path buffer overflow\n");
-		return (NULL);
+		    "ai_du_get_manual_pkg_list: origin path buffer overflow\n");
+		return (AUTO_INSTALL_FAILURE);
 	}
 
 	/* Get real origins list here for use below. */
 	origins = ai_get_manifest_values(path_p->path_str, &origin_len);
 
 	/*
-	 * Not a perfect test to validate pkg specs and origins in manifest,
-	 * but it will do...
+	 * Not a perfect test to validate package specs vs origins in
+	 * manifest, but it will do...
 	 */
-	if (origin_len != num_pkg_specs) {
+	if (origin_len != num_pkgspecs) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
-		    "ai_du_get_pkg_list: <add_drivers> manifest error:\n"
-		    "There is not a 1-1 origin to pkg spec mapping.\n");
-		return (NULL);
+		    "ai_du_get_manual_pkg_list: <add_drivers> manifest error:\n"
+		    "There is not a 1-1 <origin> - <software> mapping.\n");
+		ai_free_manifest_values(origins);
+		return (AUTO_INSTALL_FAILURE);
 	}
 
 	uniq_origins = ai_uniq_manifest_values(origins, &origin_len);
@@ -1008,15 +1259,9 @@
 	origins = uniq_origins;
 
 	/*
-	 * Initialize a zero-length list.
-	 * This will be returned empty if nothing to install has been found.
-	 */
-	pPackageList = PyList_New(0);
-
-	/*
-	 * For each origin, get types.  Note it is possible for there to be
-	 * more than one type at a origin.  There can also be more than one
-	 * item of a given type at a origin.
+	 * For each origin (location), get types.  Note it is possible for
+	 * there to be more than one type at an origin.  There can also be more
+	 * than one item of a given type at an origin.
 	 */
 	for (i = 0; i < origin_len; i++) {
 
@@ -1025,18 +1270,20 @@
 		if (snprintf(path_p->post_prefix_start, path_p->post_prefix_len,
 		    TYPE_NODEPATH, origins[i]) >= path_p->post_prefix_len) {
 			auto_debug_print(AUTO_DBGLVL_ERR,
-			    "ai_du_get_pkg_list: "
+			    "ai_du_get_manual_pkg_list: "
 			    "<add_drivers> manifest error:\n"
 			    "type path buffer overflow for origin %s\n",
 			    origins[i]);
+			rval = AUTO_INSTALL_FAILURE;
 			continue;
 		}
 
 		types = ai_get_manifest_values(path_p->path_str, &typelen);
 		if (typelen <= 0) {
-			auto_log_print(gettext("ai_du_get_pkg_list: "
+			auto_log_print(gettext("Add Drivers: "
 			    "<add_drivers> manifest error:\n"
 			    "no type given for origin %s\n"), origins[i]);
+			rval = AUTO_INSTALL_FAILURE;
 			continue;
 		}
 
@@ -1047,14 +1294,18 @@
 		/* Loop for all types found at this origin... */
 		for (j = 0; j < typelen; j++) {
 
-			/* Obj pointed to by pPackageList will be modified. */
-			ai_du_process_manual_pkg_types(py_state_p, pPackageList,
-			    path_p, origins[i], types[j]);
+			/* Obj *pPackageList_p points to will be modified.  */
+			int status = ai_du_process_manual_pkg_types(py_state_p,
+			    *pPackageList_p, path_p, origins[i], types[j]);
+			if (status == AUTO_INSTALL_FAILURE) {
+				rval = AUTO_INSTALL_FAILURE;
+			}
 		}
 	}
+
 	ai_free_manifest_values(origins);
 	ai_free_manifest_values(types);
-	return (pPackageList);
+	return (rval);
 }
 
 /*
@@ -1065,38 +1316,51 @@
  * checking of the manifest as necessary, as this function reads the manifest
  * before it is validated against a schema.
  *
+ * Always return a list.  An empty list can be returned if a search determines
+ * there are no packages to install for Driver Update (i.e. the system is
+ * missing no drivers), or on some errors.
+ *
  * Validates syntax and processes the following from the manifest:
  *	<add_drivers>
  *		<search_all addall="false">
  *			<source>
  *				<publisher name="publisher">
- *					<origin name="origin"/>
+ *					<origin name="location"/>
  *				</publisher>
  *			</source>
  *		</search_all>
  *	</add_drivers>
  *
- *  publisher and origin are both optional, but if one is specified then the
- *  other must also be specified.
- *	addall is optional.  Defaults to "false" if not specified.
+ *	publisher and origin are both optional, but if one is specified then
+ *		the other must also be specified.
+ *
+ *	addall is optional.  When true, it allows search_all to install third
+ *	party drivers (found via the database in the given pkg(5) repository,
+ *	but installed from somewhere else).  Defaults to "false" if not
+ *	specified.
  *
  * Arguments:
  *   py_state_p: Initialized py_state_t object.
  *   path_p: Used to build nodepath strings for manifest checking.
+ *   install_root: Root used for determining pkg publisher.
+ *   pPackageList_p: A python list of (ddu_package_object, third_party_ok,
+ *	noinstall) tuples suitable for input to ai_du_install_packages().
  *
  * Returns:
- *   Success: A python list of (ddu_package_object, third_party_ok, noinstall)
- *	tuples suitable for input to ai_du_install_packages().
- *	NOTE: if the system is missing no drivers, this function will return
- *	an empty list.
- *   Failure: NULL
+ *   AUTO_INSTALL_SUCCESS: No errors were encountered in retrieving package
+ *	information.  It is also possible that the system is missing no drivers,
+ *	and an empty list is returned.
+ *   AUTO_INSTALL_PKG_NOT_FND: Packages for one or more missing drivers are not
+ *	available.
+ *   AUTO_INSTALL_FAILURE: One or more errors (other than packages which were
+ *	not available) were encountered in retrieving package information.
  *
  * NOTE: check installer logfile for details of the failure.
  */
-static PyObject *
-ai_du_get_searched_pkg_list(py_state_t *py_state_p, path_t *path_p)
+static int
+ai_du_get_searched_pkg_list(py_state_t *py_state_p, path_t *path_p,
+    char *install_root, PyObject **pPackageList_p)
 {
-	PyObject *pPackageList = NULL;
 	PyObject *pDeviceList = NULL;
 	PyObject *pTuple;
 	PyObject *pRepoTupleList;
@@ -1109,9 +1373,9 @@
 	char **search_pubs = NULL;
 	char **search_addalls = NULL;
 	Py_ssize_t i, listlen;
-	PyObject *pRval = NULL;
+	int rval = AUTO_INSTALL_FAILURE;
 
-	pPackageList = PyList_New(0); /* Initialize a zero-length list. */
+	*pPackageList_p = PyList_New(0); /* Initialize a zero-length list. */
 
 	/* Read manifest for search requests. */
 
@@ -1120,21 +1384,22 @@
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "ai_du_get_searched_pkg_list: "
 		    "search pathname buffer overflow.\n");
-		return (NULL);
+		return (AUTO_INSTALL_FAILURE);
 	}
 
 	searches = ai_get_manifest_values(path_p->path_str, &len);
 	ai_free_manifest_values(searches);
 	if (len > 1) {
-		auto_log_print(gettext("ai_du_get_searched_pkg_list: "
-		    "too many <search_all> entries in manifest\n"));
-		return (NULL);
-
-	} else if (len <= 0) {
-		return (pPackageList);
+		auto_log_print(gettext("Add Drivers: "
+		    "Only one <search_all> entry allowed in manifest\n"));
+		return (AUTO_INSTALL_FAILURE);
 	}
 
-	auto_log_print(gettext("ai_du_get_searched_pkg_list: Doing a device "
+	if (len <= 0) {
+		return (AUTO_INSTALL_SUCCESS);
+	}
+
+	auto_log_print(gettext("Add Drivers: Doing a device "
 	    "scan for devices which are missing drivers...\n"));
 
 	/*
@@ -1145,25 +1410,27 @@
 	if (pDeviceList == NULL) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "ai_du_get_searched_pkg_list: "
-		    "Error scanning for missing devices.\n");
-		return (NULL);
+		    "Error scanning for missing drivers.\n");
+		return (AUTO_INSTALL_FAILURE);
 
 	/* An empty list is perfectly acceptable here.  No missing drivers. */
 	} else if (PyList_Size(pDeviceList) == 0) {
-		return (pPackageList);
+		auto_debug_print(AUTO_DBGLVL_ERR,
+		    "ai_du_get_searched_pkg_list: No missing drivers found.\n");
+		return (AUTO_INSTALL_SUCCESS);
 	}
 
-	/* Get repo origin, if specified. */
+	/* Get repo location, if specified. */
 
 	if (strlcpy(path_p->post_prefix_start, SEARCH_ORIGIN_NODEPATH,
 	    path_p->post_prefix_len) > path_p->post_prefix_len) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "ai_du_get_searched_pkg_list: search repo origin path "
 		    "buffer overflow.\n");
-		return (NULL);
+		return (AUTO_INSTALL_FAILURE);
 	}
 
-	auto_log_print(gettext("ai_du_get_searched_pkg_list: Querying manifest "
+	auto_log_print(gettext("Add Drivers: Querying manifest "
 	    "for explicit repo for getting missing driver packages...\n"));
 
 	search_origins = ai_get_manifest_values(path_p->path_str, &sublen);
@@ -1172,7 +1439,7 @@
 	} else if (sublen <= 0) {
 		search_origin = empty_string;
 	} else {
-		auto_log_print(gettext("ai_du_get_searched_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "<add_drivers> manifest error:\n"
 		    "Only one origin allowed per <search_all> entry.\n"));
 		goto done;
@@ -1194,7 +1461,7 @@
 	} else if (sublen <= 0) {
 		search_pub = empty_string;
 	} else {
-		auto_log_print(gettext("ai_du_get_searched_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "<add_drivers> manifest error:\n"
 		    "Only one publisher allowed for a <search_all> entry\n"));
 		goto done;
@@ -1203,7 +1470,7 @@
 	/* Can't have one without the other. */
 	if ((search_pub == empty_string) ^
 	    (search_origin == empty_string)) {
-		auto_log_print(gettext("ai_du_get_searched_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "<add_drivers> manifest error:\n"
 		    "search repo origin and "
 		    "publisher must be specified together.\n"));
@@ -1216,15 +1483,17 @@
 	 */
 	if (search_pub != empty_string) {
 
-		auto_log_print(gettext("ai_du_get_searched_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "Found repo in manifest: publisher:%s, origin:%s\n"),
 		    search_pub, search_origin);
 
 		pTuple = PyTuple_New(2);
-		PyTuple_SetItem(pTuple, 0, PyString_FromString(search_pub));
-		PyTuple_SetItem(pTuple, 1, PyString_FromString(search_origin));
+		(void) PyTuple_SetItem(pTuple, 0,
+		    PyString_FromString(search_pub));
+		(void) PyTuple_SetItem(pTuple, 1,
+		    PyString_FromString(search_origin));
 		pRepoTupleList = PyList_New(0);
-		PyList_Append(pRepoTupleList, pTuple);
+		(void) PyList_Append(pRepoTupleList, pTuple);
 		pSearchRepoList = ai_call_ddu_build_repo_list(py_state_p,
 		    pRepoTupleList);
 		Py_DECREF(pTuple);
@@ -1236,12 +1505,31 @@
 			    "Error building search repo list.\n");
 			goto done;
 		}
+
+		auto_log_print(gettext("Add Drivers: "
+		    "Searching for packages in %s repository at %s\n"),
+		    search_pub, search_origin);
+
 	} else {
+		FILE *pub_info;
+		char pub_buf[MAXPATHLEN];
+		char cmd_buf[MAXPATHLEN];
+
 		/* No publisher/URL provided.  Return an empty repo list. */
 
-		auto_debug_print(AUTO_DBGLVL_INFO,
-		    "ai_du_get_searched_pkg_list: "
-		    "No <search_all> repo found in manifest\n");
+		auto_log_print(gettext("Add Drivers: "
+		    "No explicit <search_all> repo specified in manifest\n"));
+		auto_log_print(gettext("... Searching for packages in "
+		    "repositories already configured on the system\n"));
+
+		(void) snprintf(cmd_buf, MAXPATHLEN,
+		    "/usr/bin/pkg -R %s publisher", install_root);
+		if ((pub_info = popen(cmd_buf, "r")) != NULL) {
+			while (fgets(pub_buf, MAXPATHLEN, pub_info) != NULL) {
+				auto_log_print("%s\n", pub_buf);
+			}
+			(void) pclose(pub_info);
+		}
 
 		pSearchRepoList = PyList_New(0);
 	}
@@ -1262,7 +1550,7 @@
 	    ((sublen == 1) &&
 	    ((strcmp(search_addalls[0], "true") != 0) &&
 	    (strcmp(search_addalls[0], "false") != 0)))) {
-		auto_log_print(gettext("ai_du_get_searched_pkg_list: "
+		auto_log_print(gettext("Add Drivers: "
 		    "<add_drivers> manifest error:\n"
 		    "invalid addall value for <search_all> entry\n"));
 		goto done;
@@ -1273,7 +1561,7 @@
 		py_search_addall = Py_False;
 
 	} else {
-		auto_log_print(gettext("ai_du_get_searched_pkg_list: Manifest "
+		auto_log_print(gettext("Add Drivers: Manifest "
 		    "allows adding of third-party drivers\n"));
 		Py_INCREF(Py_True);
 		py_search_addall = Py_True;
@@ -1283,6 +1571,7 @@
 	 * Append packages found for missing devices, to the list of packages
 	 * to install.
 	 */
+	rval = AUTO_INSTALL_SUCCESS;
 	listlen = PyList_Size(pDeviceList);
 	for (i = 0; i < listlen; i++) {
 
@@ -1290,30 +1579,45 @@
 		PyObject *pDDUDevData;
 		char *dev_type;
 		char *descr;
+		int lookup_err;
 		boolean_t third_party = B_FALSE;
 
 		pDDUDevData = PyList_GetItem(pDeviceList, i);
 
 		/* Find the package containing the driver for this device. */
-		pDDUPackageObject = ai_call_ddu_package_lookup(py_state_p,
-		    pDDUDevData, pSearchRepoList);
+		lookup_err = ai_call_ddu_package_lookup(py_state_p,
+		    pDDUDevData, pSearchRepoList, &pDDUPackageObject);
 
 		/* Get info for display / logging purposes, and log it. */
-		if (ai_get_ddu_dev_data_values(pDDUDevData,
-		    &dev_type, &descr) != AUTO_INSTALL_SUCCESS) {
+		if (ai_get_ddu_dev_data_values(pDDUDevData, &dev_type, &descr,
+		    NULL, NULL, NULL) != AUTO_INSTALL_SUCCESS) {
 			auto_debug_print(AUTO_DBGLVL_ERR,
 			    "ai_du_get_searched_pkg_list: Error retrieving "
 			    "device information for display\n");
 			dev_type = descr = empty_string;
 		}
 
-		if (pDDUPackageObject == NULL) {
-			auto_log_print(gettext("ai_du_get_searched_pkg_list: "
+		/* Package not found is not considered an error. */
+		if (lookup_err == AUTO_INSTALL_PKG_NOT_FND) {
+			auto_log_print(gettext("Add Drivers: "
+			    "Warning: Search found no package for "
+			    "\"%s\" type device \"%s\".\n"), dev_type, descr);
+			/*
+			 * Set marginal success status.
+			 * Don't override failure status.
+			 */
+			if (rval == AUTO_INSTALL_SUCCESS) {
+				rval = AUTO_INSTALL_PKG_NOT_FND;
+			}
+			continue;
+		} else if (lookup_err != AUTO_INSTALL_SUCCESS) {
+			auto_log_print(gettext("Add Drivers: "
 			    "Error retrieving package for "
 			    "\"%s\" type device \"%s\".\n"), dev_type, descr);
+			rval = AUTO_INSTALL_FAILURE;
 			continue;
 		} else {
-			auto_log_print(gettext("ai_du_get_searched_pkg_list: "
+			auto_log_print(gettext("Add Drivers: "
 			    "DDU returned package info for "
 			    "\"%s\" type device \"%s\".\n"), dev_type, descr);
 		}
@@ -1332,18 +1636,13 @@
 		 * steal a reference to it.
 		 */
 		pTuple = PyTuple_New(3);
-		PyTuple_SetItem(pTuple, 0, pDDUPackageObject);
-		Py_INCREF(py_search_addall);
-		PyTuple_SetItem(pTuple, 1, py_search_addall); /* 3rd party OK */
-		Py_INCREF(Py_False);
-		PyTuple_SetItem(pTuple, 2, Py_False);	/* always install */
-
-		PyList_Append(pPackageList, pTuple);
+		(void) PyTuple_SetItem(pTuple, 0, pDDUPackageObject);
+		Py_INCREF(py_search_addall);	/* 3rd party OK */
+		(void) PyTuple_SetItem(pTuple, 1, py_search_addall);
+		Py_INCREF(Py_False);		/* always install */
+		(void) PyTuple_SetItem(pTuple, 2, Py_False);
+		(void) PyList_Append(*pPackageList_p, pTuple);
 	}
-
-	/* Success.  Prepare to return the package list just prepared. */
-	pRval = pPackageList;
-
 done:
 	/* Cleanup time, whether an error occured or not. */
 	ai_free_manifest_values(search_origins);
@@ -1351,7 +1650,7 @@
 	Py_XDECREF(py_search_addall);
 	Py_XDECREF(pSearchRepoList);
 	Py_XDECREF(pDeviceList);
-	return (pRval);
+	return (rval);
 }
 
 /*
@@ -1360,6 +1659,9 @@
  * tree under install_root, skipping packages with noinstall flag set if
  * honor_noinstall is set.
  *
+ * NOTE: it is assumed that the DDU library returns successful status when
+ * attempting to install a package which is already installed.
+ *
  * Arguments:
  *   py_state_p: Initialized py_state_t object.
  *   pPkgTupleList: Python list of (ddu_package_object, third_party_ok,
@@ -1391,7 +1693,7 @@
 	Py_ssize_t i;
 	int rval = AUTO_INSTALL_SUCCESS;
 
-	auto_log_print(gettext("ai_du_install_packages: "
+	auto_log_print(gettext("Add Drivers: "
 	    "Installing packages to %s\n"), install_root);
 
 	len = PyList_Size(pPkgTupleList);
@@ -1403,36 +1705,32 @@
 		PyObject *pDDUPackageObject = PyTuple_GetItem(pTuple, 0);
 		PyObject *pThirdPartyOK = PyTuple_GetItem(pTuple, 1);
 		PyObject *pNoInstall = PyTuple_GetItem(pTuple, 2);
-		char *type = empty_string;
-		char *origin = empty_string;
-		char *name = empty_string;
-		char *descr = empty_string;
-		char *inf_link = empty_string;
+		char *type, *location, *name, *descr, *inf_link;
 		boolean_t third_party;
 
 		if (ai_get_ddu_package_object_values(pDDUPackageObject,
-		    &type, &origin, &name, &descr, &inf_link, &third_party) !=
+		    &type, &location, &name, &descr, &inf_link, &third_party) !=
 		    AUTO_INSTALL_SUCCESS) {
 			auto_debug_print(AUTO_DBGLVL_ERR,
 			    "ai_du_install_packages: Error extracting package "
 			    "information for ddu_package_object.\n");
-			type = origin = name = descr = inf_link =
+			type = location = name = descr = inf_link =
 			    empty_string;
 			third_party = B_FALSE;
 		} else {
 			if (strcmp(name, empty_string) == 0) {
 				auto_log_print(gettext(
 				    "  %s package at origin:%s\n"),
-				    type, origin);
+				    type, location);
 			} else {
 				auto_log_print(gettext(
 				    "  %s package at origin:%s, name:%s\n"),
-				    type, origin, name);
+				    type, location, name);
 			}
 		}
 
 		if (PyObject_IsTrue(pNoInstall) && honor_noinstall) {
-			auto_log_print(gettext("ai_du_install_packages: "
+			auto_log_print(gettext("Add Drivers: "
 			    "    honoring noinstall: skipping package.\n"));
 			continue;
 		}
@@ -1455,16 +1753,15 @@
 		}
 
 		/* Handle uninstallable package objects. */
-		if (strcmp(origin, empty_string) == 0) {
+		if (strcmp(location, empty_string) == 0) {
 			if (strcmp(inf_link, empty_string) == 0) {
 				auto_log_print(gettext(
-				    "ai_du_install_packages: Package not "
+				    "Add Drivers: Package not "
 				    "found for device: \"%s\"\n"), descr);
 			} else {
 				auto_log_print(gettext(
-				    "ai_du_install_packages: Package for "
-				    "device: \"%s\" must be installed "
-				    "manually.\n"
+				    "Add Drivers: Package for device: \"%s\" "
+				    "must be installed manually.\n"
 				    "For more information go to:\n %s\n"),
 				    descr, inf_link);
 			}
@@ -1476,7 +1773,7 @@
 		if (ai_call_ddu_install_package(py_state_p, pDDUPackageObject,
 		    install_root, PyObject_IsTrue(pThirdPartyOK)) ==
 		    AUTO_INSTALL_FAILURE) {
-			auto_log_print(gettext("ai_du_install_packages: "
+			auto_log_print(gettext("Add Drivers: "
 			    "Error installing package to %s\n"), install_root);
 			rval = AUTO_INSTALL_FAILURE;
 		} else {
@@ -1526,6 +1823,9 @@
 	}
 
 	out = (char **)malloc((in_len - dup_count + 1) * sizeof (char *));
+	if (out == NULL) {
+		return (NULL);
+	}
 	for (i = 0, j = 0; i < in_len; i++) {
 		if (!is_dup[i]) {
 			out[j++] = strdup(in[i]);
@@ -1566,20 +1866,19 @@
 	} else {
 		/* Set up args to python function. */
 		PyObject *pArgs = PyTuple_New(1);
-		PyTuple_SetItem(pArgs, 0, PyString_FromString(install_root));
+		(void) PyTuple_SetItem(pArgs, 0,
+		    PyString_FromString(install_root));
 
 		/* Call constructor. */
 		pICT_instance = PyObject_CallObject(pFunc, pArgs);
 		Py_XDECREF(pFunc);
 		Py_DECREF(pArgs);
-		if ((PyErr_Occurred()) || (pICT_instance == NULL) ||
+		if ((PyErr_Occurred() != NULL) || (pICT_instance == NULL) ||
 		    (pICT_instance == Py_None)) {
 			auto_debug_dump_file(AUTO_DBGLVL_ERR, DDU_ERRLOG);
 			auto_debug_print(AUTO_DBGLVL_ERR,
 			    "ICT constructor failed\n");
-			if (PyErr_Occurred()) {
-				PyErr_Print();
-			}
+			ai_dump_python_exception();
 			Py_CLEAR(pICT_instance);
 		}
 	}
@@ -1618,6 +1917,18 @@
  * This is to handle any explicit requests for matching a special driver to a
  * device, before <search_all> finds the first available one.
  *
+ * If search determines that a driver is missing and cannot find a package for
+ * it, this is not reported as an error.  A ddu_package_object is not created in
+ * this case, so no installation or package fetch is done for this driver.  Any
+ * other kind of problem which occurs around searched packages, during the
+ * search itself or during an installation of a package found during search, is
+ * reported as an error.
+ *
+ * Any issue found around explicitly specified packages (<software>s), whether
+ * it be that the package is not found or there was an issue during
+ * installation, is reported as an error.  ddu_package_objects are always
+ * created for these packages.
+ *
  * Assumes ai_create_manifest_image() has set up the manifest data.
  * Does not assume any data has been verified though.
  *
@@ -1627,15 +1938,23 @@
  *   honor_noinstall: When true and the noinstall flag is set in a package
  *	tuple, skip installing that package.
  *   update_boot_archive: When true, run the ICT to update the boot archive.
+ *   num_pkgs_installed_p: Returns the number of packages installed.
  *
  * Returns:
- *   The number of packages successfully processed if all are successfully
- *	processed.  NOTE: this can be zero if there are none to process.
- *   -1: One or more packages could not be successfully processed.
+ *   AUTO_INSTALL_SUCCESS: No errors found.
+ *   AUTO_INSTALL_PKG_NOT_FND: At least one needed package found during search
+ *	could not be found.  No other errors encountered.
+ *   AUTO_INSTALL_FAILURE: An error was encountered and was different than
+ *	not being able to find a package for a missing driver.
+ *
  *   Boot archive update status is not reflected in this return status.
  *   NOTE: this routine will continue on most errors, in order to install as
  *	many packages as possible.
  *
+ * NOTE: return status and num_pkgs_installed together tell the caller the full
+ * story.  It is possible, for example, that no packages were installed because
+ * one package flagged during search could not be found.
+ *
  * NOTE: check installer logfile for details of the failure.
  *
  * Side effects:
@@ -1643,7 +1962,7 @@
  */
 int
 ai_du_get_and_install(char *install_root, boolean_t honor_noinstall,
-    boolean_t update_boot_archive)
+    boolean_t update_boot_archive, int *num_installed_pkgs_p)
 {
 	PyObject *manual_pkg_list;
 	PyObject *searched_pkg_list;
@@ -1654,8 +1973,9 @@
 	int len;
 	Py_ssize_t manual_size = 0;
 	Py_ssize_t searched_size = 0;
-	int rval = 0;
-	int num_pkgs_installed = 0;
+	int rval = AUTO_INSTALL_SUCCESS;
+
+	*num_installed_pkgs_p = 0;
 
 	/* Initialize path, post_prefix_start and post_prefix_len for later. */
 	(void) strncpy(path.path_str, AIM_PREFACE, MAX_NODEPATH_SIZE);
@@ -1674,37 +1994,37 @@
 	py_pkg_list = PyList_New(0);
 
 	/*
-	 * See if the manifest has at least one pkg spec or searchall entry.
+	 * See if the manifest has at least one <software> or search_all entry.
 	 * If not, just return success (e.g. no-op).
 	 */
 
-	/* Get the number of pkg spec entries. */
+	/* Get the number of <software> entries. */
 	if (strlcpy(path.post_prefix_start, PKGSPEC_NODEPATH,
 	    path.post_prefix_len) > path.post_prefix_len) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
-		    "ai_du_get_and_install: pkg spec path buffer overflow\n");
-		return (-1);
+		    "ai_du_get_and_install: <software> path buffer overflow\n");
+		return (AUTO_INSTALL_FAILURE);
 	}
 
-	/* Get number of pkg spec entries in the manifest. */
+	/* Get number of <software> entries in the manifest. */
 	dummy_list = ai_get_manifest_values(path.path_str, &num_entries);
 	ai_free_manifest_values(dummy_list);
 
 	if (num_entries <= 0) {
-		/* See if there is a searchall entry in the manifest. */
+		/* See if there is a search_all entry in the manifest. */
 		if (strlcpy(path.post_prefix_start, SEARCH_NODEPATH,
 		    path.post_prefix_len) > path.post_prefix_len) {
 			auto_debug_print(AUTO_DBGLVL_ERR,
 			    "ai_du_get_and_install: "
 			    "search path buffer overflow\n");
-			return (-1);
+			return (AUTO_INSTALL_FAILURE);
 		}
 
 		dummy_list = ai_get_manifest_values(path.path_str,
 		    &num_entries);
 		ai_free_manifest_values(dummy_list);
 		if (num_entries <= 0) {
-			return (0);
+			return (AUTO_INSTALL_SUCCESS);
 		}
 	}
 
@@ -1720,57 +2040,65 @@
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "ai_du_get_and_install: "
 		    "Error initializing auto_ddu_lib.\n");
-		rval = -1;
+		rval = AUTO_INSTALL_FAILURE;
 		goto done;
 	}
 
-	manual_pkg_list = ai_du_get_manual_pkg_list(py_state_p, &path);
-	if (manual_pkg_list == NULL) {
+	if (ai_du_get_manual_pkg_list(py_state_p, &path,
+	    &manual_pkg_list) != AUTO_INSTALL_SUCCESS) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "ai_du_get_and_install: "
-		    "Error getting package specification.\n");
-		rval = -1;
+		    "Error getting <software> package specification.\n");
+		rval = AUTO_INSTALL_FAILURE;
 		/* Keep going.  Don't abort. */
-	} else {
-		manual_size = PyList_Size(manual_pkg_list);
-		if (manual_size > 0) {
-			if (ai_du_install_packages(py_state_p, manual_pkg_list,
-			    install_root, honor_noinstall,
-			    &num_pkgs_installed) != AUTO_INSTALL_SUCCESS) {
-				auto_debug_print(AUTO_DBGLVL_ERR,
-				    "ai_du_get_and_install: Error installing "
-				    "at least one package.\n");
-				rval = -1;
-				/* Keep going.  Don't abort. */
-			}
+	}
+
+	manual_size = PyList_Size(manual_pkg_list);
+	if (manual_size > 0) {
+		if (ai_du_install_packages(py_state_p, manual_pkg_list,
+		    install_root, honor_noinstall, num_installed_pkgs_p) !=
+		    AUTO_INSTALL_SUCCESS) {
+			auto_debug_print(AUTO_DBGLVL_ERR,
+			    "ai_du_get_and_install: Error installing at least "
+			    "one <software> package specification.\n");
+			rval = AUTO_INSTALL_FAILURE;
+			/* Keep going.  Don't abort. */
 		}
 	}
 
-	searched_pkg_list = ai_du_get_searched_pkg_list(py_state_p, &path);
-	if (searched_pkg_list == NULL) {
+	switch (ai_du_get_searched_pkg_list(py_state_p, &path, install_root,
+	    &searched_pkg_list)) {
+	case AUTO_INSTALL_FAILURE:
+		rval = AUTO_INSTALL_FAILURE;
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "ai_du_get_and_install: "
 		    "Error searching for inoperable devices and "
 		    "missing driver packages.\n");
-		rval = -1;
 		/* Keep going.  Don't abort. */
-	} else {
-		searched_size = PyList_Size(searched_pkg_list);
-		if (searched_size > 0) {
-			if (ai_du_install_packages(py_state_p,
-			    searched_pkg_list, install_root, honor_noinstall,
-			    &num_pkgs_installed) != AUTO_INSTALL_SUCCESS) {
-				auto_debug_print(AUTO_DBGLVL_ERR,
-				    "ai_du_get_and_install: Error installing "
-				    "at least one searched package "
-				    "for <search_all>.\n");
-				rval = -1;
-				/* Keep going.  Don't abort. */
-			}
+		break;
+	case AUTO_INSTALL_PKG_NOT_FND:
+		if (rval != AUTO_INSTALL_FAILURE) {
+			rval = AUTO_INSTALL_PKG_NOT_FND;
+		}
+		break;
+	default:
+		break;
+	}
+
+	searched_size = PyList_Size(searched_pkg_list);
+	if (searched_size > 0) {
+		if (ai_du_install_packages(py_state_p, searched_pkg_list,
+		    install_root, honor_noinstall, num_installed_pkgs_p) !=
+		    AUTO_INSTALL_SUCCESS) {
+			auto_debug_print(AUTO_DBGLVL_ERR,
+			    "ai_du_get_and_install: Error installing at least "
+			    "one searched package for <search_all>.\n");
+			rval = AUTO_INSTALL_FAILURE;
+			/* Keep going.  Don't abort. */
 		}
 	}
 
-	if ((update_boot_archive) && (num_pkgs_installed > 0)) {
+	if (update_boot_archive && (*num_installed_pkgs_p > 0)) {
 		if (ai_du_call_update_archive_ict(py_state_p, install_root) !=
 		    AUTO_INSTALL_SUCCESS) {
 			auto_debug_print(AUTO_DBGLVL_ERR,
@@ -1785,20 +2113,20 @@
 	 */
 
 	if (manual_size > 0) {
-		PyList_SetSlice(py_pkg_list, 0, manual_size - 1,
+		(void) PyList_SetSlice(py_pkg_list, 0, manual_size - 1,
 		    manual_pkg_list);
 	}
+	Py_DECREF(manual_pkg_list);
 
 	if (searched_size > 0) {
-		PyList_SetSlice(py_pkg_list, manual_size,
+		(void) PyList_SetSlice(py_pkg_list, manual_size,
 		    manual_size + searched_size - 1, searched_pkg_list);
 	}
+	Py_DECREF(searched_pkg_list);
+
 done:
 	auto_ddu_lib_fini(py_state_p);
 
-	if (rval != -1) {
-		rval = num_pkgs_installed;
-	}
 	return (rval);
 }
 
@@ -1813,9 +2141,9 @@
  * This routine assumes the py_pkg_list was set up via a prior call to
  * ai_du_get_and_install_packages().
  *
- * The availability and origin of all packages to be installed is assumed the
- * same as when the py_pkg_list was built (i.e. the most recent call to
- * ai_du_get_and_install()).
+ * The availability and origin (location) of all packages to be installed is
+ * assumed the same as when the py_pkg_list was built (i.e. the most recent
+ * call to ai_du_get_and_install()).
  *
  * Arguments:
  *   install_root: Top of the filesystem or tree where the packages are to be
@@ -1823,51 +2151,62 @@
  *   honor_noinstall: When true and the noinstall flag is set in a package
  *	tuple, skip installing that package.
  *   update_boot_archive: When true, run the ICT to update the boot archive.
+ *   num_installed_pkgs_p: Returns the number of packages successfully
+ *	installed.
  *   NOTE: the modular global py_pkg_list specifies the packages to install.
  *
  * Returns:
- *   The number of packages successfully processed if all are successfully
- *	processed.  NOTE: this can be zero if there are none to process.
- *   -1: At least one package was not able to be installed.
+ *   AUTO_INSTALL_SUCCESS: No errors found and at least one package was
+ *	installed.
+ *   AUTO_INSTALL_FAILURE: An error was encountered.  Some packages may have
+ *	been installed.
+ *
  *   Boot archive update status is not reflected in this return status.
+ *   NOTE: this routine will continue on most errors, in order to install as
+ *	many packages as possible.
+ *
+ * NOTE: return status and num_pkgs_installed together tell the caller the full
+ * story.  It is possible, for example, that no packages were installed because
+ * one package flagged during search could not be found.
  *
  * NOTE: check installer logfile for details of the failure.
  */
 int
 ai_du_install(char *install_root, boolean_t honor_noinstall,
-    boolean_t update_boot_archive)
+    boolean_t update_boot_archive, int *num_installed_pkgs_p)
 {
-	int rval = 0;
-	int num_pkgs_installed = 0;
+	int rval = AUTO_INSTALL_SUCCESS;
 
 	py_state_t *py_state_p;
 
+	*num_installed_pkgs_p = 0;
+
 	if (py_pkg_list == NULL) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "ai_du_install: ai_du_get_and_install needs to be "
 		    "called first.\n");
-		return (-1);
+		return (AUTO_INSTALL_FAILURE);
 
 	} else if (PyList_Size(py_pkg_list) == 0) {
-		return (num_pkgs_installed);
+		return (AUTO_INSTALL_SUCCESS);
 	}
 
 	if ((py_state_p = auto_ddu_lib_init()) == NULL) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "ai_du_install: "
 		    "Error initializing auto_ddu_lib.\n");
-		return (-1);
+		return (AUTO_INSTALL_FAILURE);
 	}
 
 	if ((rval = ai_du_install_packages(py_state_p, py_pkg_list,
-	    install_root, honor_noinstall, &num_pkgs_installed)) !=
+	    install_root, honor_noinstall, num_installed_pkgs_p)) !=
 	    AUTO_INSTALL_SUCCESS) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "ai_du_install: Error installing packages.\n");
-		rval = -1;
+		rval = AUTO_INSTALL_FAILURE;
 	}
 
-	if (update_boot_archive && (num_pkgs_installed > 0)) {
+	if (update_boot_archive && (*num_installed_pkgs_p > 0)) {
 		if (ai_du_call_update_archive_ict(py_state_p,
 		    install_root) != AUTO_INSTALL_SUCCESS) {
 			auto_debug_print(AUTO_DBGLVL_ERR,
@@ -1876,10 +2215,6 @@
 		}
 	}
 
-	if (rval != -1) {
-		rval = num_pkgs_installed;
-	}
-
 	auto_ddu_lib_fini(py_state_p);
 
 	return (rval);
--- a/usr/src/cmd/auto-install/auto_install.c	Mon Aug 30 15:52:14 2010 -0700
+++ b/usr/src/cmd/auto-install/auto_install.c	Mon Aug 30 15:53:34 2010 -0700
@@ -188,7 +188,7 @@
 	}
 
 	/* Use buffer to set up the command. */
-	snprintf(buffer, MAXPATHLEN, "/usr/bin/cat %s", filename);
+	(void) snprintf(buffer, MAXPATHLEN, "/usr/bin/cat %s", filename);
 	if ((file_ptr = popen(buffer, "r")) == NULL) {
 		auto_debug_print(AUTO_DBGLVL_ERR,
 		    "Error opening ddu errlog %s to dump errors: %s\n",
@@ -292,25 +292,25 @@
 			 * of SC manifest with following string:
 			 * "<?xml version='1.0'?>\n"
 			 */
-			fputs(SC_MANIFEST_BEGIN_MARKER, scfp);
-			fputs("\n", scfp);
+			(void) fputs(SC_MANIFEST_BEGIN_MARKER, scfp);
+			(void) fputs("\n", scfp);
 			continue;
 		}
 		if (writing_ai_manifest) {
-			fputs(buf, aifp);
+			(void) fputs(buf, aifp);
 			continue;
 		} else if (writing_sc_manifest) {
 			if (strstr(buf, SC_MANIFEST_END_MARKER) != NULL) {
 				writing_sc_manifest = B_FALSE;
 			}
-			fputs(buf, scfp);
+			(void) fputs(buf, scfp);
 			continue;
 		}
 	}
 
-	fclose(ifp);
-	fclose(aifp);
-	fclose(scfp);
+	(void) fclose(ifp);
+	(void) fclose(aifp);
+	(void) fclose(scfp);
 	return (AUTO_VALID_MANIFEST);
 }
 
@@ -393,7 +393,14 @@
 			    "No install package list given, using default\n");
 
 			num_packages = 4;
-			package_list = malloc((num_packages + 1) * sizeof (char *));
+			package_list =
+			    malloc((num_packages + 1) * sizeof (char *));
+			if (package_list == NULL) {
+				auto_debug_print(AUTO_DBGLVL_ERR,
+				    "No memory.\n");
+				(void) fclose(fp);
+				return (AUTO_INSTALL_FAILURE);
+			}
 			package_list[0] = strdup("pkg:/SUNWcsd");
 			package_list[1] = strdup("pkg:/SUNWcs");
 			package_list[2] = strdup("pkg:/babel_install");
@@ -1050,7 +1057,11 @@
 
 		proxy_len = strlen("http_proxy=") + strlen(p) + 1;
 		proxy = malloc(proxy_len);
-		snprintf(proxy, proxy_len, "%s%s", "http_proxy=", p);
+		if (proxy == NULL) {
+			auto_debug_print(AUTO_DBGLVL_ERR, "No memory.\n");
+			goto error_ret;
+		}
+		(void) snprintf(proxy, proxy_len, "%s%s", "http_proxy=", p);
 		auto_debug_print(AUTO_DBGLVL_INFO,
 		    "Setting http_proxy environment variable to %s\n", p);
 		if (putenv(proxy)) {
@@ -1845,24 +1856,20 @@
 		/*
 		 * Install any drivers required for installation, in the
 		 * booted environment.
-		 */
-
-		/*
+		 *
+		 * Don't fail the whole installation if ai_du_get_and_install()
+		 * fails here.  This operation affects only the booted
+		 * environment.  It is possible that a package missing here will
+		 * already be included in the target install, so let the
+		 * installation proceed.  If something critical is still
+		 * missing, the target install will fail anyway.
+		 *
 		 * First boolean: do not honor noinstall flag.
 		 * Second boolean: do not update the boot archive.
 		 */
-		num_du_pkgs_installed =
-		    ai_du_get_and_install("/", B_FALSE, B_FALSE);
-
-		/*
-		 * Note: Print no messages if num_du_pkgs_installed = 0
-		 * This means no packages and no errors, or no-op.
-		 */
-		if (num_du_pkgs_installed > 0) {
-			auto_log_print(gettext("All additional "
-			    "driver packages successfully installed "
-			    "to booted installation environment.\n"));
-		} else if (num_du_pkgs_installed < 0) {
+		if (ai_du_get_and_install("/", B_FALSE, B_FALSE,
+		    &num_du_pkgs_installed) != AUTO_INSTALL_SUCCESS) {
+			/* Handle failure or "package not found" statuses. */
 			char *du_warning = gettext("Warning: some additional "
 			    "driver packages could not be installed\n"
 			    "  to booted installation environment.\n"
@@ -1871,6 +1878,15 @@
 			    "  Will continue anyway...\n");
 			auto_log_print(du_warning);
 			(void) fprintf(stderr, du_warning);
+
+		} else if (num_du_pkgs_installed > 0) {
+			/*
+			 * Note: Print no messages if num_du_pkgs_installed = 0
+			 * This means no packages and no errors, or no-op.
+			 */
+			auto_log_print(gettext("Add Drivers: All required "
+			    "additional driver packages successfully installed "
+			    "to booted installation environment.\n"));
 		}
 
 		diskname[0] = '\0';
@@ -1909,9 +1925,8 @@
 		 * First boolean: honor noinstall flag.
 		 * Second boolean: update boot archive.
 		 */
-		num_du_pkgs_installed =
-		    ai_du_install(INSTALLED_ROOT_DIR, B_TRUE, B_TRUE);
-		if (num_du_pkgs_installed < 0) {
+		if (ai_du_install(INSTALLED_ROOT_DIR, B_TRUE, B_TRUE,
+		    &num_du_pkgs_installed) == AUTO_INSTALL_FAILURE) {
 			char *tgt_inst_err = gettext("Basic installation was "
 			    "successful.  However, there was an error\n");
 			auto_log_print(tgt_inst_err, profile);
--- a/usr/src/cmd/auto-install/auto_install.h	Mon Aug 30 15:52:14 2010 -0700
+++ b/usr/src/cmd/auto-install/auto_install.h	Mon Aug 30 15:53:34 2010 -0700
@@ -44,11 +44,12 @@
 #define	AI_EXIT_FAILURE		1	/* general failure */
 #define	AI_EXIT_FAILURE_AIM	2	/* failure-invalid manifest provided */
 
-#define	AUTO_INSTALL_SUCCESS	0
-#define	AUTO_INSTALL_EMPTY_LIST	1	/* list of packages is empty */
-#define	AUTO_INSTALL_FAILURE	-1
-#define	AUTO_TD_SUCCESS		0
-#define	AUTO_TD_FAILURE		-1
+#define	AUTO_INSTALL_SUCCESS		0
+#define	AUTO_INSTALL_EMPTY_LIST		1	/* list of packages is empty */
+#define	AUTO_INSTALL_PKG_NOT_FND	2
+#define	AUTO_INSTALL_FAILURE		-1
+#define	AUTO_TD_SUCCESS			0
+#define	AUTO_TD_FAILURE			-1
 
 #define	INSTALLED_ROOT_DIR	"/a"
 #define	AUTO_UNKNOWN_STRING	"unknown"
@@ -98,32 +99,41 @@
 	((units) == AI_SIZE_UNITS_SECTORS ? "sectors": \
 	"(unknown)"))))
 
-#define MB_TO_SECTORS	((uint64_t)2048)
-#define GB_TO_MB	((uint64_t)1024)
-#define TB_TO_GB	((uint64_t)1024)
+#define	MB_TO_SECTORS	((uint64_t)2048)
+#define	GB_TO_MB	((uint64_t)1024)
+#define	TB_TO_GB	((uint64_t)1024)
 
 
 /*
  * DTD schema nodepaths - see ai.dtd
  */
-#define	AIM_TARGET_DISK_KEYWORD "auto_install/ai_instance/target/target_device/disk/disk_keyword/key"
-#define	AIM_TARGET_DEVICE_NAME "auto_install/ai_instance/target/target_device/disk/disk_name[name_type='ctd']/name"
+#define	AIM_TARGET_DISK_KEYWORD "auto_install/ai_instance/" \
+	"target/target_device/disk/disk_keyword/key"
+#define	AIM_TARGET_DEVICE_NAME "auto_install/ai_instance/" \
+	"target/target_device/disk/disk_name[name_type='ctd']/name"
 #define	AIM_TARGET_DEVICE_BOOT_DISK "boot_disk"
 #define	AIM_TARGET_DEVICE_SELECT_VOLUME_NAME \
-	"auto_install/ai_instance/target/target_device/disk/disk_name[name_type='volid']/name"
+	"auto_install/ai_instance/target/target_device/" \
+	"disk/disk_name[name_type='volid']/name"
 #define	AIM_TARGET_DEVICE_SELECT_DEVICE_ID \
-	"auto_install/ai_instance/target/target_device/disk/disk_name[name_type='devid']/name"
+	"auto_install/ai_instance/target/target_device/" \
+	"disk/disk_name[name_type='devid']/name"
 #define	AIM_TARGET_DEVICE_SELECT_DEVICE_PATH \
-	"auto_install/ai_instance/target/target_device/disk/disk_name[name_type='devpath']/name"
-#define	AIM_TARGET_DEVICE_TYPE "auto_install/ai_instance/target/target_device/disk/disk_prop/dev_type"
+	"auto_install/ai_instance/target/target_device/" \
+	"disk/disk_name[name_type='devpath']/name"
+#define	AIM_TARGET_DEVICE_TYPE "auto_install/ai_instance/" \
+	"target/target_device/disk/disk_prop/dev_type"
 #define	AIM_TARGET_DEVICE_SIZE	\
-	"auto_install/ai_instance/target/target_device/disk/disk_prop/dev_size"
-#define	AIM_TARGET_DEVICE_VENDOR	\
-	"auto_install/ai_instance/target/target_device/disk/disk_prop/dev_vendor"
+	"auto_install/ai_instance/target/target_device/" \
+	"disk/disk_prop/dev_size"
+#define	AIM_TARGET_DEVICE_VENDOR "auto_install/ai_instance/target/" \
+	"target_device/disk/disk_prop/dev_vendor"
 #define	AIM_TARGET_DEVICE_USE_SOLARIS_PARTITION	\
-	"auto_install/ai_instance/target/target_device/disk/partition[action='use_existing']/action"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[action='use_existing']/action"
 #define	AIM_TARGET_DEVICE_INSTALL_SLICE_NUMBER \
-	"auto_install/ai_instance/target/target_device/disk/slice[is_root='true']/name"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"slice[is_root='true']/name"
 #define	AIM_TARGET_DEVICE_ISCSI_TARGET_NAME \
 	"auto_install/ai_instance/target/target_device/disk/iscsi/name"
 #define	AIM_TARGET_DEVICE_ISCSI_TARGET_IP \
@@ -144,41 +154,57 @@
 #define	AIM_NUMBERED_PARTITIONS	\
 	"auto_install/ai_instance/target/target_device/disk/partition/name"
 #define	AIM_NUMBERED_PARTITION_NUMBER	\
-	"auto_install/ai_instance/target/target_device/disk/partition[name=\"%s\":action=\"%s\"]/name"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[name=\"%s\":action=\"%s\"]/name"
 #define	AIM_NUMBERED_PARTITION_ACTION	\
-	"auto_install/ai_instance/target/target_device/disk/partition[name=\"%s\":action=\"%s\"]/action"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[name=\"%s\":action=\"%s\"]/action"
 #define	AIM_NUMBERED_PARTITION_START_SECTOR	\
-	"auto_install/ai_instance/target/target_device/disk/partition[name=\"%s\":action=\"%s\"]/size/start_sector"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[name=\"%s\":action=\"%s\"]/size/start_sector"
 #define	AIM_NUMBERED_PARTITION_SIZE	\
-	"auto_install/ai_instance/target/target_device/disk/partition[name=\"%s\":action=\"%s\"]/size/val"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[name=\"%s\":action=\"%s\"]/size/val"
 #define	AIM_NUMBERED_PARTITION_TYPE	\
-	"auto_install/ai_instance/target/target_device/disk/partition[name=\"%s\":action=\"%s\"]/part_type"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[name=\"%s\":action=\"%s\"]/part_type"
 
 #define	AIM_USE_EXISTING_PARTITIONS	\
-	"auto_install/ai_instance/target/target_device/disk/partition[action='use_existing']/action"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[action='use_existing']/action"
 #define	AIM_UNNUMBERED_PARTITION_NUMBER	\
-	"auto_install/ai_instance/target/target_device/disk/partition[action='use_existing']/name"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[action='use_existing']/name"
 #define	AIM_UNNUMBERED_PARTITION_ACTION	\
-	"auto_install/ai_instance/target/target_device/disk/partition[action='use_existing']/action"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[action='use_existing']/action"
 #define	AIM_UNNUMBERED_PARTITION_START_SECTOR	\
-	"auto_install/ai_instance/target/target_device/disk/partition[action='use_existing']/size/start_sector"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[action='use_existing']/size/start_sector"
 #define	AIM_UNNUMBERED_PARTITION_SIZE	\
-	"auto_install/ai_instance/target/target_device/disk/partition[action='use_existing']/size/val"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[action='use_existing']/size/val"
 #define	AIM_UNNUMBERED_PARTITION_TYPE	\
-	"auto_install/ai_instance/target/target_device/disk/partition[action='use_existing']/part_type"
+	"auto_install/ai_instance/target/target_device/disk/" \
+	"partition[action='use_existing']/part_type"
 
-#define	AIM_SLICE_NUMBER "auto_install/ai_instance/target/target_device/disk/slice/name"
-#define	AIM_SLICE_ACTION "auto_install/ai_instance/target/target_device/disk/slice/action"
-#define	AIM_SLICE_SIZE "auto_install/ai_instance/target/target_device/disk/slice[name=\"%s\":action=\"%s\"]/size/val"
-#define	AIM_SLICE_ON_EXISTING	\
-	"auto_install/ai_instance/target/target_device/disk/slice[name=\"%s\":action=\"%s\"]/force"
+#define	AIM_SLICE_NUMBER "auto_install/ai_instance/target/" \
+	"target_device/disk/slice/name"
+#define	AIM_SLICE_ACTION "auto_install/ai_instance/target/" \
+	"target_device/disk/slice/action"
+#define	AIM_SLICE_SIZE "auto_install/ai_instance/target/" \
+	"target_device/disk/slice[name=\"%s\":action=\"%s\"]/size/val"
+#define	AIM_SLICE_ON_EXISTING "auto_install/ai_instance/target/" \
+	"target_device/disk/slice[name=\"%s\":action=\"%s\"]/force"
 #define	AIM_AUTO_REBOOT	"auto_install/ai_instance/auto_reboot"
 
 #define	AIM_PROXY_URL "auto_install/ai_instance/http_proxy"
 
-#define	AIM_PACKAGE_INSTALL_NAME "auto_install/ai_instance/software/software_data[action='install']/name"
+#define	AIM_PACKAGE_INSTALL_NAME "auto_install/ai_instance/software/" \
+	"software_data[action='install']/name"
 
-#define	AIM_PACKAGE_REMOVE_NAME "auto_install/ai_instance/software/software_data[action='uninstall']/name"
+#define	AIM_PACKAGE_REMOVE_NAME "auto_install/ai_instance/software/" \
+	"software_data[action='uninstall']/name"
 
 /*
  * Primary and secondary publishers
@@ -191,10 +217,10 @@
 /*
  * Find publisher name and mirror based on url
  */
-#define	AIM_ADD_URL_PUBLISHER_NAME \
-	"auto_install/ai_instance/software/source/publisher[origin/name=\"%s\"]/name"
-#define	AIM_ADD_URL_PUBLISHER_MIRROR \
-	"auto_install/ai_instance/software/source/publisher[origin/name=\"%s\"]/mirror/name"
+#define	AIM_ADD_URL_PUBLISHER_NAME "auto_install/ai_instance/software/" \
+	"source/publisher[origin/name=\"%s\"]/name"
+#define	AIM_ADD_URL_PUBLISHER_MIRROR "auto_install/ai_instance/software/" \
+	"source/publisher[origin/name=\"%s\"]/mirror/name"
 
 /* type of package list to be obtained from manifest */
 typedef enum {
@@ -343,9 +369,9 @@
 void	ai_free_manifest_value_list(char **value_list);
 
 int	ai_du_get_and_install(char *install_root, boolean_t honor_noinstall,
-	    boolean_t update_boot_archive);
+	    boolean_t update_boot_archive, int *num_installed_pkgs_p);
 int	ai_du_install(char *install_root, boolean_t honor_noinstall,
-	    boolean_t update_boot_archive);
+	    boolean_t update_boot_archive, int *num_installed_pkgs_p);
 
 int	mount_iscsi_target_if_requested(auto_disk_info *, char *, int);
 
--- a/usr/src/cmd/auto-install/default.xml	Mon Aug 30 15:52:14 2010 -0700
+++ b/usr/src/cmd/auto-install/default.xml	Mon Aug 30 15:53:34 2010 -0700
@@ -63,17 +63,14 @@
         <name>pkg:/slim_install</name>
       </software_data>
     </software>
-    <!--
+   <!--
 	Add missing driver packages to a booted install image so an
 	installation can complete.  Add packages to target as well.
 	<search_all> searches and installs from configured repo.
     -->
-    <!--
-                Uncomment before using
-            <add_drivers>
-                <search_all/>
-            </add_drivers>
-	-->
+    <add_drivers>
+      <search_all/>
+    </add_drivers>
     <sc_embedded_manifest name="AI">
       <!-- <?xml version='1.0'?>
       <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">