6978976 AI manifest <searchall> should be more forgiving of missing packages.
authorJack Schwartz <Jack.Schwartz@Oracle.COM>
Wed, 25 Aug 2010 14:54:09 -0700
changeset 867 cfbbedf29419
parent 866 98116df00176
child 868 ccab1050a371
6978976 AI manifest <searchall> should be more forgiving of missing packages. 6978978 DDU install should log what pkg repo they are trying to get packages from 6978979 AI Driver Update code needs to check for duplicate driver requests 6978971 Handling of expected DDU Python exceptions shouldn't display tracebacks in AI logfiles 6978972 Preface Driver Update messages with more useful <add_drivers> instead of function names
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/cmd/auto-install/auto_ddu_lib.c	Tue Aug 24 08:14:38 2010 -0700
+++ b/usr/src/cmd/auto-install/auto_ddu_lib.c	Wed Aug 25 14:54:09 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	Tue Aug 24 08:14:38 2010 -0700
+++ b/usr/src/cmd/auto-install/auto_install.c	Wed Aug 25 14:54:09 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	Tue Aug 24 08:14:38 2010 -0700
+++ b/usr/src/cmd/auto-install/auto_install.h	Wed Aug 25 14:54:09 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	Tue Aug 24 08:14:38 2010 -0700
+++ b/usr/src/cmd/auto-install/default.xml	Wed Aug 25 14:54:09 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">