2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <libxml/parser.h>
2N/A#include <libxml/xinclude.h>
2N/A#include <sys/fm/protocol.h>
2N/A#include <alloca.h>
2N/A#include <assert.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <ctype.h>
2N/A#include <errno.h>
2N/A#include <limits.h>
2N/A#include <fm/libtopo.h>
2N/A#include <unistd.h>
2N/A#include <sys/stat.h>
2N/A#include <fcntl.h>
2N/A#include <topo_file.h>
2N/A#include <topo_mod.h>
2N/A#include <topo_subr.h>
2N/A#include <topo_alloc.h>
2N/A#include <topo_parse.h>
2N/A#include <topo_error.h>
2N/A
2N/Astatic tf_rdata_t *topo_xml_walk(topo_mod_t *, tf_info_t *, xmlNodePtr,
2N/A tnode_t *);
2N/Astatic tf_edata_t *enum_attributes_process(topo_mod_t *, xmlNodePtr);
2N/Astatic int enum_run(topo_mod_t *, tf_rdata_t *);
2N/Astatic int fac_enum_run(topo_mod_t *, tnode_t *, const char *);
2N/Astatic int fac_process(topo_mod_t *, xmlNodePtr, tf_rdata_t *, tnode_t *);
2N/Astatic int fac_enum_process(topo_mod_t *, xmlNodePtr, tnode_t *);
2N/Astatic int decorate_nodes(topo_mod_t *, tf_rdata_t *, xmlNodePtr, tnode_t *,
2N/A tf_pad_t **);
2N/A
2N/A
2N/Astatic void
2N/Astrarr_free(topo_mod_t *mod, char **arr, uint_t nelems)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < nelems; i++)
2N/A topo_mod_strfree(mod, arr[i]);
2N/A topo_mod_free(mod, arr, (nelems * sizeof (char *)));
2N/A}
2N/A
2N/Aint
2N/Axmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, const char *stabname,
2N/A topo_stability_t *rs)
2N/A{
2N/A xmlChar *str;
2N/A int rv = 0;
2N/A
2N/A if (n == NULL) {
2N/A /* If there is no Stability defined, we default to private */
2N/A *rs = TOPO_STABILITY_PRIVATE;
2N/A return (0);
2N/A }
2N/A if ((str = xmlGetProp(n, (xmlChar *)stabname)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: no attribute: %s\n", __func__, stabname);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
2N/A }
2N/A
2N/A if (xmlStrcmp(str, (xmlChar *)Internal) == 0) {
2N/A *rs = TOPO_STABILITY_INTERNAL;
2N/A } else if (xmlStrcmp(str, (xmlChar *)Private) == 0) {
2N/A *rs = TOPO_STABILITY_PRIVATE;
2N/A } else if (xmlStrcmp(str, (xmlChar *)Obsolete) == 0) {
2N/A *rs = TOPO_STABILITY_OBSOLETE;
2N/A } else if (xmlStrcmp(str, (xmlChar *)External) == 0) {
2N/A *rs = TOPO_STABILITY_EXTERNAL;
2N/A } else if (xmlStrcmp(str, (xmlChar *)Unstable) == 0) {
2N/A *rs = TOPO_STABILITY_UNSTABLE;
2N/A } else if (xmlStrcmp(str, (xmlChar *)Evolving) == 0) {
2N/A *rs = TOPO_STABILITY_EVOLVING;
2N/A } else if (xmlStrcmp(str, (xmlChar *)Stable) == 0) {
2N/A *rs = TOPO_STABILITY_STABLE;
2N/A } else if (xmlStrcmp(str, (xmlChar *)Standard) == 0) {
2N/A *rs = TOPO_STABILITY_STANDARD;
2N/A } else {
2N/A xmlFree(str);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_BADSTAB));
2N/A }
2N/A xmlFree(str);
2N/A return (rv);
2N/A}
2N/A
2N/Aint
2N/Axmlattr_to_int(topo_mod_t *mp,
2N/A xmlNodePtr n, const char *propname, uint64_t *value)
2N/A{
2N/A xmlChar *str;
2N/A xmlChar *estr;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: propname=%s\n",
2N/A __func__, propname);
2N/A if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL)
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: str=%s\n", __func__, str);
2N/A *value = strtoull((char *)str, (char **)&estr, 10);
2N/A if (estr == str) {
2N/A /* no conversion was done */
2N/A xmlFree(str);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM));
2N/A }
2N/A xmlFree(str);
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Axmlattr_to_fmri(topo_mod_t *mp,
2N/A xmlNodePtr xn, const char *propname, nvlist_t **rnvl)
2N/A{
2N/A xmlChar *str;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: PROPNAME=%s\n",
2N/A __func__, propname);
2N/A if ((str = xmlGetProp(xn, (xmlChar *)propname)) == NULL)
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: str=%s\n", __func__, str);
2N/A if (topo_mod_str2nvl(mp, (const char *)str, rnvl) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: "
2N/A "topo_mod_str2nvl() failed, str=%s\n", __func__, str);
2N/A xmlFree(str);
2N/A return (-1);
2N/A }
2N/A xmlFree(str);
2N/A return (0);
2N/A}
2N/A
2N/Astatic topo_type_t
2N/Axmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn, xmlChar *attr)
2N/A{
2N/A topo_type_t rv;
2N/A xmlChar *str;
2N/A if ((str = xmlGetProp(xn, (xmlChar *)attr)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: %s attribute missing", __func__, attr);
2N/A (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
2N/A return (TOPO_TYPE_INVALID);
2N/A }
2N/A if (xmlStrcmp(str, (xmlChar *)Int32) == 0) {
2N/A rv = TOPO_TYPE_INT32;
2N/A } else if (xmlStrcmp(str, (xmlChar *)UInt32) == 0) {
2N/A rv = TOPO_TYPE_UINT32;
2N/A } else if (xmlStrcmp(str, (xmlChar *)Int64) == 0) {
2N/A rv = TOPO_TYPE_INT64;
2N/A } else if (xmlStrcmp(str, (xmlChar *)UInt64) == 0) {
2N/A rv = TOPO_TYPE_UINT64;
2N/A } else if (xmlStrcmp(str, (xmlChar *)FMRI) == 0) {
2N/A rv = TOPO_TYPE_FMRI;
2N/A } else if (xmlStrcmp(str, (xmlChar *)String) == 0) {
2N/A rv = TOPO_TYPE_STRING;
2N/A } else if (xmlStrcmp(str, (xmlChar *)Int32_Arr) == 0) {
2N/A rv = TOPO_TYPE_INT32_ARRAY;
2N/A } else if (xmlStrcmp(str, (xmlChar *)UInt32_Arr) == 0) {
2N/A rv = TOPO_TYPE_UINT32_ARRAY;
2N/A } else if (xmlStrcmp(str, (xmlChar *)Int64_Arr) == 0) {
2N/A rv = TOPO_TYPE_INT64_ARRAY;
2N/A } else if (xmlStrcmp(str, (xmlChar *)UInt64_Arr) == 0) {
2N/A rv = TOPO_TYPE_UINT64_ARRAY;
2N/A } else if (xmlStrcmp(str, (xmlChar *)String_Arr) == 0) {
2N/A rv = TOPO_TYPE_STRING_ARRAY;
2N/A } else if (xmlStrcmp(str, (xmlChar *)FMRI_Arr) == 0) {
2N/A rv = TOPO_TYPE_FMRI_ARRAY;
2N/A } else {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: unrecognized type attribute value '%s'\n",
2N/A __func__, str);
2N/A (void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
2N/A xmlFree(str);
2N/A return (TOPO_TYPE_INVALID);
2N/A }
2N/A xmlFree(str);
2N/A return (rv);
2N/A}
2N/A
2N/Astatic int
2N/Axlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
2N/Aconst char *name)
2N/A{
2N/A int rv;
2N/A uint64_t ui;
2N/A uint_t i = 0, nelems = 0;
2N/A nvlist_t *fmri;
2N/A xmlChar *str;
2N/A char **strarrbuf;
2N/A void *arrbuf;
2N/A nvlist_t **nvlarrbuf;
2N/A xmlNodePtr cn;
2N/A char *token = NULL;
2N/A boolean_t array_workaround = B_FALSE;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: name=%s\n",
2N/A __func__, name);
2N/A switch (ptype) {
2N/A case TOPO_TYPE_INT32:
2N/A if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
2N/A return (-1);
2N/A rv = nvlist_add_int32(nvl, name, (int32_t)ui);
2N/A break;
2N/A case TOPO_TYPE_UINT32:
2N/A if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
2N/A return (-1);
2N/A rv = nvlist_add_uint32(nvl, name, (uint32_t)ui);
2N/A break;
2N/A case TOPO_TYPE_INT64:
2N/A if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
2N/A return (-1);
2N/A rv = nvlist_add_int64(nvl, name, (int64_t)ui);
2N/A break;
2N/A case TOPO_TYPE_UINT64:
2N/A if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
2N/A return (-1);
2N/A rv = nvlist_add_uint64(nvl, name, ui);
2N/A break;
2N/A case TOPO_TYPE_FMRI:
2N/A if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "%s: "
2N/A "xmlattr_to_fmri() failed\n", __func__);
2N/A return (-1);
2N/A }
2N/A rv = nvlist_add_nvlist(nvl, name, fmri);
2N/A nvlist_free(fmri);
2N/A break;
2N/A case TOPO_TYPE_STRING:
2N/A if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL)
2N/A return (-1);
2N/A rv = nvlist_add_string(nvl, name, (char *)str);
2N/A xmlFree(str);
2N/A break;
2N/A case TOPO_TYPE_INT32_ARRAY:
2N/A case TOPO_TYPE_UINT32_ARRAY:
2N/A case TOPO_TYPE_INT64_ARRAY:
2N/A case TOPO_TYPE_UINT64_ARRAY:
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
2N/A if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
2N/A (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0))
2N/A nelems++;
2N/A
2N/A if (nelems == 0) {
2N/A topo_dprintf(mp->tm_hdl,
2N/A (ptype == TOPO_TYPE_UINT32_ARRAY ?
2N/A TOPO_DBG_SNAP : TOPO_DBG_ERR | TOPO_DBG_SNAP),
2N/A "%s: no <propitem> or <argitem> elements found "
2N/A "for array val, name=%s", __func__, name);
2N/A if (ptype != TOPO_TYPE_UINT32_ARRAY)
2N/A return (-1);
2N/A /*
2N/A * This is a workaround for xml integer arrays not
2N/A * being in the proper XML format. See topo_2xml.c.
2N/A * Try interpreting it as a string.
2N/A */
2N/A if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: failed to interpret as a string\n",
2N/A __func__);
2N/A return (-1);
2N/A } else {
2N/A char *str2;
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_SNAP,
2N/A "%s: interpreting array as a string, "
2N/A "str=%s\n", __func__, str);
2N/A /*
2N/A * See how many elements we have by parsing
2N/A * a duplicate string.
2N/A */
2N/A str2 = (char *)alloca(strlen((char *)str));
2N/A (void) strcpy(str2, (char *)str);
2N/A for (token = strtok(str2, " "); token != NULL;
2N/A token = strtok(NULL, " "))
2N/A nelems++;
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_SNAP,
2N/A "%s: nelem=%d\n", __func__, nelems);
2N/A if (nelems == 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: no elements found, str=%s\n",
2N/A __func__, str);
2N/A xmlFree(str);
2N/A return (-1);
2N/A }
2N/A array_workaround = B_TRUE;
2N/A }
2N/A }
2N/A if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (uint64_t))))
2N/A == NULL)
2N/A return (topo_mod_seterrno(mp, ETOPO_NOMEM));
2N/A break;
2N/A case TOPO_TYPE_STRING_ARRAY:
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
2N/A if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
2N/A (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0))
2N/A nelems++;
2N/A
2N/A if (nelems == 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: no <propitem> or <argitem> elements found "
2N/A "for array val", __func__);
2N/A return (-1);
2N/A }
2N/A if ((strarrbuf = topo_mod_alloc(mp, (nelems * sizeof (char *))))
2N/A == NULL)
2N/A return (topo_mod_seterrno(mp, ETOPO_NOMEM));
2N/A break;
2N/A case TOPO_TYPE_FMRI_ARRAY:
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
2N/A if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
2N/A (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0))
2N/A nelems++;
2N/A
2N/A if (nelems == 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: no <propitem> elements found for array prop",
2N/A __func__);
2N/A return (-1);
2N/A }
2N/A if ((nvlarrbuf = topo_mod_alloc(mp, (nelems *
2N/A sizeof (nvlist_t *)))) == NULL)
2N/A return (topo_mod_seterrno(mp, ETOPO_NOMEM));
2N/A break;
2N/A default:
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: unrecognized type attribute (ptype = %d)\n",
2N/A __func__, ptype);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE));
2N/A }
2N/A
2N/A switch (ptype) {
2N/A case TOPO_TYPE_INT32_ARRAY:
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
2N/A (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
2N/A
2N/A if ((str = xmlGetProp(xn, (xmlChar *)Value))
2N/A == NULL)
2N/A return (-1);
2N/A
2N/A ((int32_t *)arrbuf)[i++]
2N/A = atoi((const char *)str);
2N/A xmlFree(str);
2N/A }
2N/A }
2N/A
2N/A rv = nvlist_add_int32_array(nvl, name, (int32_t *)arrbuf,
2N/A nelems);
2N/A topo_mod_free(mp, arrbuf, (nelems * sizeof (uint64_t)));
2N/A break;
2N/A case TOPO_TYPE_UINT32_ARRAY:
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
2N/A (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
2N/A
2N/A if ((str = xmlGetProp(xn, (xmlChar *)Value))
2N/A == NULL)
2N/A return (-1);
2N/A
2N/A ((uint64_t *)arrbuf)[i++]
2N/A = atol((const char *)str);
2N/A xmlFree(str);
2N/A }
2N/A }
2N/A if (array_workaround == B_TRUE) {
2N/A /* Parse the string and fill in the array. */
2N/A for (token = strtok((char *)str, " "); token != NULL;
2N/A token = strtok(NULL, " ")) {
2N/A ((uint32_t *)arrbuf)[i++]
2N/A = strtoul((const char *)token,
2N/A (char **)NULL, 16);
2N/A }
2N/A xmlFree(str);
2N/A /* Sanity check that we parsed the same number. */
2N/A if (i != nelems) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_SNAP,
2N/A "%s: i=%d != nelems=%d\n",
2N/A __func__, i, nelems);
2N/A return (-1);
2N/A }
2N/A }
2N/A rv = nvlist_add_uint32_array(nvl, name, (uint32_t *)arrbuf,
2N/A nelems);
2N/A topo_mod_free(mp, arrbuf, (nelems * sizeof (uint64_t)));
2N/A break;
2N/A case TOPO_TYPE_INT64_ARRAY:
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
2N/A (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
2N/A
2N/A if ((str = xmlGetProp(xn, (xmlChar *)Value))
2N/A == NULL)
2N/A return (-1);
2N/A
2N/A ((int64_t *)arrbuf)[i++]
2N/A = atol((const char *)str);
2N/A xmlFree(str);
2N/A }
2N/A }
2N/A
2N/A rv = nvlist_add_int64_array(nvl, name, (int64_t *)arrbuf,
2N/A nelems);
2N/A topo_mod_free(mp, arrbuf, (nelems * sizeof (uint64_t)));
2N/A break;
2N/A case TOPO_TYPE_UINT64_ARRAY:
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
2N/A (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
2N/A
2N/A if ((str = xmlGetProp(xn, (xmlChar *)Value))
2N/A == NULL)
2N/A return (-1);
2N/A
2N/A ((uint64_t *)arrbuf)[i++]
2N/A = atol((const char *)str);
2N/A xmlFree(str);
2N/A }
2N/A }
2N/A
2N/A rv = nvlist_add_uint64_array(nvl, name, arrbuf, nelems);
2N/A topo_mod_free(mp, arrbuf, (nelems * sizeof (uint64_t)));
2N/A break;
2N/A case TOPO_TYPE_STRING_ARRAY:
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
2N/A (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
2N/A
2N/A if ((str = xmlGetProp(cn, (xmlChar *)Value))
2N/A == NULL)
2N/A return (-1);
2N/A
2N/A strarrbuf[i++] =
2N/A topo_mod_strdup(mp, (const char *)str);
2N/A xmlFree(str);
2N/A }
2N/A }
2N/A
2N/A rv = nvlist_add_string_array(nvl, name, strarrbuf, nelems);
2N/A strarr_free(mp, strarrbuf, nelems);
2N/A break;
2N/A case TOPO_TYPE_FMRI_ARRAY:
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
2N/A (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
2N/A
2N/A if ((str = xmlGetProp(xn, (xmlChar *)Value))
2N/A == NULL)
2N/A return (-1);
2N/A
2N/A if (topo_mod_str2nvl(mp, (const char *)str,
2N/A &(nvlarrbuf[i++])) < 0) {
2N/A xmlFree(str);
2N/A return (-1);
2N/A }
2N/A xmlFree(str);
2N/A }
2N/A }
2N/A
2N/A rv = nvlist_add_nvlist_array(nvl, name, nvlarrbuf,
2N/A nelems);
2N/A topo_mod_free(mp, arrbuf, (nelems * sizeof (nvlist_t *)));
2N/A break;
2N/A }
2N/A
2N/A if (rv != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: nvlist construction failed\n", __func__);
2N/A return (topo_mod_seterrno(mp, ETOPO_NOMEM));
2N/A } else
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Axmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl)
2N/A{
2N/A topo_type_t ptype;
2N/A xmlChar *str;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s:\n", __func__);
2N/A if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) {
2N/A if (xmlStrcmp(str, (xmlChar *)False) == 0)
2N/A (void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
2N/A B_FALSE);
2N/A else
2N/A (void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
2N/A B_TRUE);
2N/A xmlFree(str);
2N/A } else {
2N/A (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE);
2N/A }
2N/A
2N/A if ((ptype = xmlattr_to_type(mp, xn, (xmlChar *)Type))
2N/A == TOPO_TYPE_INVALID)
2N/A return (-1);
2N/A
2N/A if (nvlist_add_int32(nvl, INV_PVALTYPE, ptype) != 0)
2N/A return (-1);
2N/A
2N/A return (xlate_common(mp, xn, ptype, nvl, INV_PVAL));
2N/A}
2N/A
2N/Astatic int
2N/Adependent_create(topo_mod_t *mp,
2N/A tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr dxn, tnode_t *ptn)
2N/A{
2N/A tf_rdata_t *rp, *pp, *np;
2N/A xmlChar *grptype;
2N/A int sibs = 0;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s:\n", __func__);
2N/A if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: dependents missing grouping attribute", __func__);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
2N/A }
2N/A
2N/A pp = NULL;
2N/A if (xmlStrcmp(grptype, (xmlChar *)Siblings) == 0) {
2N/A rp = pad->tpad_sibs;
2N/A sibs++;
2N/A } else if (xmlStrcmp(grptype, (xmlChar *)Children) == 0) {
2N/A rp = pad->tpad_child;
2N/A } else {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: dependents have bogus grouping attribute", __func__);
2N/A xmlFree(grptype);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_BADGRP));
2N/A }
2N/A xmlFree(grptype);
2N/A /* Add processed dependents to the tail of the list */
2N/A while (rp != NULL) {
2N/A pp = rp;
2N/A rp = rp->rd_next;
2N/A }
2N/A if ((np = topo_xml_walk(mp, xinfo, dxn, ptn)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: error within dependent .xml topology: %s\n",
2N/A __func__, topo_strerror(topo_mod_errno(mp)));
2N/A return (-1);
2N/A }
2N/A if (pp != NULL)
2N/A pp->rd_next = np;
2N/A else if (sibs == 1)
2N/A pad->tpad_sibs = np;
2N/A else
2N/A pad->tpad_child = np;
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Adependents_create(topo_mod_t *mp,
2N/A tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr pxn, tnode_t *ptn)
2N/A{
2N/A xmlNodePtr cn;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s:\n", __func__);
2N/A for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) {
2N/A if (dependent_create(mp, xinfo, pad, cn, ptn) < 0)
2N/A return (-1);
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aprop_create(topo_mod_t *mp,
2N/A nvlist_t *pfmri, tnode_t *ptn, const char *gnm, const char *pnm,
2N/A topo_type_t ptype, int flag)
2N/A{
2N/A nvlist_t *fmri, **fmriarr;
2N/A uint32_t ui32, *ui32arr;
2N/A uint64_t ui64, *ui64arr;
2N/A int32_t i32, *i32arr;
2N/A int64_t i64, *i64arr;
2N/A uint_t nelem;
2N/A char *str, **strarr;
2N/A int err, e;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: pgrp=%s, prop=%s\n",
2N/A __func__, gnm, pnm);
2N/A switch (ptype) {
2N/A case TOPO_TYPE_INT32:
2N/A e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32);
2N/A break;
2N/A case TOPO_TYPE_UINT32:
2N/A e = nvlist_lookup_uint32(pfmri, INV_PVAL, &ui32);
2N/A break;
2N/A case TOPO_TYPE_INT64:
2N/A e = nvlist_lookup_int64(pfmri, INV_PVAL, &i64);
2N/A break;
2N/A case TOPO_TYPE_UINT64:
2N/A e = nvlist_lookup_uint64(pfmri, INV_PVAL, &ui64);
2N/A break;
2N/A case TOPO_TYPE_FMRI:
2N/A e = nvlist_lookup_nvlist(pfmri, INV_PVAL, &fmri);
2N/A break;
2N/A case TOPO_TYPE_STRING:
2N/A e = nvlist_lookup_string(pfmri, INV_PVAL, &str);
2N/A break;
2N/A case TOPO_TYPE_INT32_ARRAY:
2N/A e = nvlist_lookup_int32_array(pfmri, INV_PVAL, &i32arr, &nelem);
2N/A break;
2N/A case TOPO_TYPE_UINT32_ARRAY:
2N/A e = nvlist_lookup_uint32_array(pfmri, INV_PVAL, &ui32arr,
2N/A &nelem);
2N/A break;
2N/A case TOPO_TYPE_INT64_ARRAY:
2N/A e = nvlist_lookup_int64_array(pfmri, INV_PVAL, &i64arr,
2N/A &nelem);
2N/A break;
2N/A case TOPO_TYPE_UINT64_ARRAY:
2N/A e = nvlist_lookup_uint64_array(pfmri, INV_PVAL, &ui64arr,
2N/A &nelem);
2N/A break;
2N/A case TOPO_TYPE_STRING_ARRAY:
2N/A e = nvlist_lookup_string_array(pfmri, INV_PVAL, &strarr,
2N/A &nelem);
2N/A break;
2N/A case TOPO_TYPE_FMRI_ARRAY:
2N/A e = nvlist_lookup_nvlist_array(pfmri, INV_PVAL, &fmriarr,
2N/A &nelem);
2N/A break;
2N/A default:
2N/A e = ETOPO_PRSR_BADTYPE;
2N/A }
2N/A if (e != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: prop value lookup failed: pgrp=%s, prop=%s\n",
2N/A __func__, gnm, pnm);
2N/A return (topo_mod_seterrno(mp, e));
2N/A }
2N/A switch (ptype) {
2N/A case TOPO_TYPE_INT32:
2N/A e = topo_prop_set_int32(ptn, gnm, pnm, flag, i32, &err);
2N/A break;
2N/A case TOPO_TYPE_UINT32:
2N/A e = topo_prop_set_uint32(ptn, gnm, pnm, flag, ui32, &err);
2N/A break;
2N/A case TOPO_TYPE_INT64:
2N/A e = topo_prop_set_int64(ptn, gnm, pnm, flag, i64, &err);
2N/A break;
2N/A case TOPO_TYPE_UINT64:
2N/A e = topo_prop_set_uint64(ptn, gnm, pnm, flag, ui64, &err);
2N/A break;
2N/A case TOPO_TYPE_FMRI:
2N/A e = topo_prop_set_fmri(ptn, gnm, pnm, flag, fmri, &err);
2N/A break;
2N/A case TOPO_TYPE_STRING:
2N/A e = topo_prop_set_string(ptn, gnm, pnm, flag, str, &err);
2N/A break;
2N/A case TOPO_TYPE_INT32_ARRAY:
2N/A e = topo_prop_set_int32_array(ptn, gnm, pnm, flag, i32arr,
2N/A nelem, &err);
2N/A break;
2N/A case TOPO_TYPE_UINT32_ARRAY:
2N/A e = topo_prop_set_uint32_array(ptn, gnm, pnm, flag, ui32arr,
2N/A nelem, &err);
2N/A break;
2N/A case TOPO_TYPE_INT64_ARRAY:
2N/A e = topo_prop_set_int64_array(ptn, gnm, pnm, flag, i64arr,
2N/A nelem, &err);
2N/A break;
2N/A case TOPO_TYPE_UINT64_ARRAY:
2N/A e = topo_prop_set_uint64_array(ptn, gnm, pnm, flag, ui64arr,
2N/A nelem, &err);
2N/A break;
2N/A case TOPO_TYPE_STRING_ARRAY:
2N/A e = topo_prop_set_string_array(ptn, gnm, pnm, flag,
2N/A (const char **)strarr, nelem, &err);
2N/A break;
2N/A case TOPO_TYPE_FMRI_ARRAY:
2N/A e = topo_prop_set_fmri_array(ptn, gnm, pnm, flag,
2N/A (const nvlist_t **)fmriarr, nelem, &err);
2N/A break;
2N/A }
2N/A if (e != 0 && err != ETOPO_PROP_DEFD) {
2N/A
2N/A /*
2N/A * Some properties may have already been set
2N/A * in topo_node_bind() or topo_prop_inherit if we are
2N/A * enumerating from a static .xml file
2N/A */
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "%s: prop set "
2N/A "failed %s/%s:%s\n", __func__, gnm, pnm,
2N/A topo_strerror(err));
2N/A return (topo_mod_seterrno(mp, err));
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aprops_create(topo_mod_t *mp,
2N/A tnode_t *ptn, const char *gnm, nvlist_t **props, int nprops)
2N/A{
2N/A topo_type_t ptype;
2N/A boolean_t pim;
2N/A char *pnm;
2N/A int32_t i32;
2N/A int flag;
2N/A int pn;
2N/A int e;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: pgrp = %s\n",
2N/A __func__, gnm);
2N/A for (pn = 0; pn < nprops; pn++) {
2N/A e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm);
2N/A if (e != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: lookup (%s) failure: %s", __func__,
2N/A INV_PNAME, strerror(e));
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
2N/A }
2N/A e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim);
2N/A if (e != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: lookup (%s) failure: %s", __func__,
2N/A INV_IMMUTE, strerror(e));
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
2N/A }
2N/A flag = (pim == B_TRUE) ?
2N/A TOPO_PROP_IMMUTABLE : TOPO_PROP_MUTABLE;
2N/A
2N/A e = nvlist_lookup_int32(props[pn], INV_PVALTYPE, &i32);
2N/A if (e != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: lookup (%s) failure: %s", __func__,
2N/A INV_PVALTYPE, strerror(e));
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
2N/A }
2N/A ptype = (topo_type_t)i32;
2N/A if (prop_create(mp, props[pn], ptn, gnm, pnm, ptype, flag) < 0)
2N/A return (-1);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Apgroups_create(topo_mod_t *mp, tf_pad_t *pad, tnode_t *ptn)
2N/A{
2N/A topo_pgroup_info_t pgi;
2N/A nvlist_t **props;
2N/A char *gnm;
2N/A char *nmstab, *dstab;
2N/A uint32_t rnprops, nprops;
2N/A uint32_t gv;
2N/A int pg;
2N/A int e;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: %s=%d\n", __func__,
2N/A topo_node_name(ptn), topo_node_instance(ptn));
2N/A for (pg = 0; pg < pad->tpad_pgcnt; pg++) {
2N/A e = nvlist_lookup_string(pad->tpad_pgs[pg],
2N/A INV_PGRP_NAME, &gnm);
2N/A if (e != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: pad lookup (%s) failed (%s)\n", __func__,
2N/A INV_PGRP_NAME, strerror(errno));
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
2N/A }
2N/A e = nvlist_lookup_string(pad->tpad_pgs[pg],
2N/A INV_PGRP_NMSTAB, &nmstab);
2N/A if (e != 0) {
2N/A if (e != ENOENT) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: pad lookup (%s) failed\n",
2N/A __func__, INV_PGRP_NMSTAB);
2N/A return (topo_mod_seterrno(mp,
2N/A ETOPO_PRSR_NVPROP));
2N/A } else {
2N/A nmstab = TOPO_STABSTR_PRIVATE;
2N/A }
2N/A }
2N/A e = nvlist_lookup_string(pad->tpad_pgs[pg],
2N/A INV_PGRP_DSTAB, &dstab);
2N/A if (e != 0) {
2N/A if (e != ENOENT) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: pad lookup (%s) failed\n", __func__,
2N/A INV_PGRP_DSTAB);
2N/A return (topo_mod_seterrno(mp,
2N/A ETOPO_PRSR_NVPROP));
2N/A } else {
2N/A dstab = TOPO_STABSTR_PRIVATE;
2N/A }
2N/A }
2N/A e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
2N/A INV_PGRP_VER, &gv);
2N/A if (e != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: pad lookup (%s) failed\n", __func__,
2N/A INV_PGRP_VER);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
2N/A }
2N/A pgi.tpi_name = gnm;
2N/A pgi.tpi_namestab = topo_name2stability(nmstab);
2N/A pgi.tpi_datastab = topo_name2stability(dstab);
2N/A pgi.tpi_version = gv;
2N/A if (topo_pgroup_create(ptn, &pgi, &e) != 0) {
2N/A if (e != ETOPO_PROP_DEFD) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: pgroups create failure: %s\n",
2N/A __func__, topo_strerror(e));
2N/A return (-1);
2N/A }
2N/A }
2N/A e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
2N/A INV_PGRP_NPROP, &rnprops);
2N/A /*
2N/A * The number of properties could be zero if the property
2N/A * group only contains propmethod declarations
2N/A */
2N/A if (rnprops > 0) {
2N/A e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg],
2N/A INV_PGRP_ALLPROPS, &props, &nprops);
2N/A if (rnprops != nprops) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: recorded number of props %d does not "
2N/A "match number of props recorded %d\n",
2N/A __func__, rnprops, nprops);
2N/A }
2N/A if (props_create(mp, ptn, gnm, props, nprops) < 0)
2N/A return (-1);
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Astatic nvlist_t *
2N/Apval_record(topo_mod_t *mp, xmlNodePtr xn)
2N/A{
2N/A nvlist_t *pnvl = NULL;
2N/A xmlChar *pname;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s:\n", __func__);
2N/A if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: propval lacks a name\n", __func__);
2N/A (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
2N/A return (NULL);
2N/A }
2N/A if (topo_mod_nvalloc(mp, &pnvl, NV_UNIQUE_NAME) < 0) {
2N/A xmlFree(pname);
2N/A return (NULL);
2N/A }
2N/A if (nvlist_add_string(pnvl, INV_PNAME, (char *)pname) < 0) {
2N/A xmlFree(pname);
2N/A nvlist_free(pnvl);
2N/A return (NULL);
2N/A }
2N/A xmlFree(pname);
2N/A /* FMXXX stability of the property name */
2N/A
2N/A if (xmlprop_xlate(mp, xn, pnvl) < 0) {
2N/A nvlist_free(pnvl);
2N/A return (NULL);
2N/A }
2N/A return (pnvl);
2N/A}
2N/A
2N/A
2N/Astruct propmeth_data {
2N/A const char *pg_name;
2N/A const char *prop_name;
2N/A topo_type_t prop_type;
2N/A const char *meth_name;
2N/A topo_version_t meth_ver;
2N/A nvlist_t *arg_nvl;
2N/A};
2N/A
2N/Astatic int
2N/Aregister_method(topo_mod_t *mp, tnode_t *ptn, struct propmeth_data *meth)
2N/A{
2N/A int err;
2N/A
2N/A if (topo_prop_method_version_register(ptn, meth->pg_name,
2N/A meth->prop_name, meth->prop_type, meth->meth_name, meth->meth_ver,
2N/A meth->arg_nvl, &err) != 0) {
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "%s: failed to register "
2N/A "propmethod %s for property \"%s\" in propgrp %s on node "
2N/A "%s=%d (%s)\n", __func__,
2N/A meth->meth_name, meth->prop_name, meth->pg_name,
2N/A topo_node_name(ptn), topo_node_instance(ptn),
2N/A topo_strerror(err));
2N/A return (-1);
2N/A }
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: registered method %s on %s=%d\n", __func__,
2N/A meth->meth_name, topo_node_name(ptn), topo_node_instance(ptn));
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Apmeth_record(topo_mod_t *mp, const char *pg_name, xmlNodePtr xn, tnode_t *tn,
2N/A const char *rname, const char *ppgrp_name)
2N/A{
2N/A nvlist_t *arg_nvl = NULL;
2N/A xmlNodePtr cn;
2N/A xmlChar *meth_name = NULL, *prop_name = NULL;
2N/A xmlChar *arg_name = NULL;
2N/A uint64_t meth_ver, is_mutable = 0, is_nonvolatile = 0;
2N/A topo_type_t prop_type;
2N/A struct propmeth_data meth;
2N/A int ret = 0, err;
2N/A topo_type_t ptype;
2N/A tnode_t *tmp;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: %s=%d (pgrp=%s)\n",
2N/A __func__, topo_node_name(tn), topo_node_instance(tn), pg_name);
2N/A
2N/A /*
2N/A * Get propmethod attribute values
2N/A */
2N/A if ((meth_name = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: propmethod element lacks a name attribute\n",
2N/A __func__);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
2N/A }
2N/A if (xmlattr_to_int(mp, xn, Version, &meth_ver) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: propmethod element lacks version attribute\n",
2N/A __func__);
2N/A ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
2N/A goto pmr_done;
2N/A }
2N/A /*
2N/A * The "mutable" and "nonvoltile" attributes are optional. If not
2N/A * specified we default to false (0)
2N/A */
2N/A (void) xmlattr_to_int(mp, xn, Mutable, &is_mutable);
2N/A (void) xmlattr_to_int(mp, xn, Nonvolatile, &is_nonvolatile);
2N/A
2N/A if ((prop_name = xmlGetProp(xn, (xmlChar *)Propname)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: propmethod element lacks propname attribute\n",
2N/A __func__);
2N/A ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
2N/A goto pmr_done;
2N/A }
2N/A if ((prop_type = xmlattr_to_type(mp, xn, (xmlChar *)Proptype))
2N/A == TOPO_TYPE_INVALID) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: error decoding proptype attribute\n", __func__);
2N/A ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
2N/A goto pmr_done;
2N/A }
2N/A
2N/A /*
2N/A * Allocate method argument nvlist
2N/A */
2N/A if (topo_mod_nvalloc(mp, &arg_nvl, NV_UNIQUE_NAME) < 0) {
2N/A ret = topo_mod_seterrno(mp, ETOPO_NOMEM);
2N/A goto pmr_done;
2N/A }
2N/A
2N/A /*
2N/A * Iterate through the argval nodes and build the argval nvlist
2N/A */
2N/A for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if (xmlStrcmp(cn->name, (xmlChar *)Argval) == 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: found argval element\n", __func__);
2N/A if ((arg_name = xmlGetProp(cn, (xmlChar *)Name))
2N/A == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: argval element lacks a name "
2N/A "attribute\n", __func__);
2N/A ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
2N/A goto pmr_done;
2N/A }
2N/A if ((ptype = xmlattr_to_type(mp, cn, (xmlChar *)Type))
2N/A == TOPO_TYPE_INVALID) {
2N/A ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
2N/A xmlFree(arg_name);
2N/A break;
2N/A }
2N/A if (xlate_common(mp, cn, ptype, arg_nvl,
2N/A (const char *)arg_name) != 0) {
2N/A ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
2N/A xmlFree(arg_name);
2N/A break;
2N/A }
2N/A }
2N/A if (arg_name) {
2N/A xmlFree(arg_name);
2N/A arg_name = NULL;
2N/A }
2N/A }
2N/A
2N/A if (ret != 0)
2N/A goto pmr_done;
2N/A
2N/A /*
2N/A * Register the prop method for all of the nodes in our range
2N/A */
2N/A meth.pg_name = (const char *)pg_name;
2N/A meth.prop_name = (const char *)prop_name;
2N/A meth.prop_type = prop_type;
2N/A meth.meth_name = (const char *)meth_name;
2N/A meth.meth_ver = meth_ver;
2N/A meth.arg_nvl = arg_nvl;
2N/A
2N/A /*
2N/A * If the propgroup element is under a range element, we'll apply
2N/A * the method to all of the topo nodes at this level with the same
2N/A * range name.
2N/A *
2N/A * Otherwise, if the propgroup element is under a node element
2N/A * then we'll simply register the method for this node.
2N/A */
2N/A if (strcmp(ppgrp_name, Range) == 0) {
2N/A for (tmp = tn; tmp != NULL; tmp = topo_child_next(NULL, tmp)) {
2N/A if (strcmp(rname, topo_node_name(tmp)) == 0) {
2N/A if (register_method(mp, tmp, &meth) != 0) {
2N/A ret = topo_mod_seterrno(mp,
2N/A ETOPO_PRSR_REGMETH);
2N/A goto pmr_done;
2N/A }
2N/A if (is_mutable) {
2N/A if (topo_prop_setmutable(tmp,
2N/A meth.pg_name, meth.prop_name, &err)
2N/A != 0) {
2N/A ret = topo_mod_seterrno(mp,
2N/A ETOPO_PRSR_REGMETH);
2N/A goto pmr_done;
2N/A }
2N/A }
2N/A if (is_nonvolatile) {
2N/A if (topo_prop_setnonvolatile(tmp,
2N/A meth.pg_name, meth.prop_name, &err)
2N/A != 0) {
2N/A ret = topo_mod_seterrno(mp,
2N/A ETOPO_PRSR_REGMETH);
2N/A goto pmr_done;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A } else {
2N/A if (register_method(mp, tn, &meth) != 0) {
2N/A ret = topo_mod_seterrno(mp, ETOPO_PRSR_REGMETH);
2N/A goto pmr_done;
2N/A }
2N/A if (is_mutable) {
2N/A if (topo_prop_setmutable(tn, meth.pg_name,
2N/A meth.prop_name, &err) != 0) {
2N/A ret = topo_mod_seterrno(mp,
2N/A ETOPO_PRSR_REGMETH);
2N/A goto pmr_done;
2N/A }
2N/A }
2N/A if (is_nonvolatile) {
2N/A if (topo_prop_setnonvolatile(tn, meth.pg_name,
2N/A meth.prop_name, &err) != 0) {
2N/A ret = topo_mod_seterrno(mp,
2N/A ETOPO_PRSR_REGMETH);
2N/A goto pmr_done;
2N/A }
2N/A }
2N/A }
2N/A
2N/Apmr_done:
2N/A if (meth_name)
2N/A xmlFree(meth_name);
2N/A if (prop_name)
2N/A xmlFree(prop_name);
2N/A if (arg_nvl)
2N/A nvlist_free(arg_nvl);
2N/A return (ret);
2N/A}
2N/A
2N/A
2N/Astatic int
2N/Apgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
2N/A tf_pad_t *rpad, int pi, const char *ppgrp_name)
2N/A{
2N/A topo_stability_t nmstab, dstab;
2N/A uint64_t ver;
2N/A xmlNodePtr cn;
2N/A xmlChar *name;
2N/A nvlist_t **apl = NULL;
2N/A nvlist_t *pgnvl = NULL;
2N/A int pcnt = 0;
2N/A int ai = 0;
2N/A int e;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: \n", __func__);
2N/A if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: propgroup lacks a name\n", __func__);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
2N/A }
2N/A if (xmlattr_to_int(mp, pxn, Version, &ver) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: propgroup lacks a version\n", __func__);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
2N/A }
2N/A if (xmlattr_to_stab(mp, pxn, Namestab, &nmstab) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: propgroup lacks name-stability\n", __func__);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
2N/A }
2N/A if (xmlattr_to_stab(mp, pxn, Datastab, &dstab) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: propgroup lacks data-stability\n", __func__);
2N/A return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
2N/A }
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: pgroup=%s\n",
2N/A __func__, (char *)name);
2N/A for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0)
2N/A pcnt++;
2N/A }
2N/A
2N/A if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) {
2N/A xmlFree(name);
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: failed to allocate propgroup nvlist\n", __func__);
2N/A return (topo_mod_seterrno(mp, ETOPO_NOMEM));
2N/A }
2N/A
2N/A e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name);
2N/A e |= nvlist_add_uint32(pgnvl, INV_PGRP_NMSTAB, nmstab);
2N/A e |= nvlist_add_uint32(pgnvl, INV_PGRP_DSTAB, dstab);
2N/A e |= nvlist_add_uint32(pgnvl, INV_PGRP_VER, ver);
2N/A e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt);
2N/A if (pcnt > 0)
2N/A if (e != 0 ||
2N/A (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *)))
2N/A == NULL) {
2N/A xmlFree(name);
2N/A nvlist_free(pgnvl);
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: failed to allocate nvlist array for "
2N/A "properties (e=%d)\n", __func__, e);
2N/A return (topo_mod_seterrno(mp, ETOPO_NOMEM));
2N/A }
2N/A for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) {
2N/A if (ai < pcnt) {
2N/A if ((apl[ai] = pval_record(mp, cn)) == NULL)
2N/A break;
2N/A }
2N/A ai++;
2N/A } else if (xmlStrcmp(cn->name, (xmlChar *)Prop_meth) == 0) {
2N/A if (pmeth_record(mp, (const char *)name, cn, tn, rname,
2N/A ppgrp_name) < 0)
2N/A break;
2N/A }
2N/A }
2N/A xmlFree(name);
2N/A if (pcnt > 0) {
2N/A e |= (ai != pcnt);
2N/A e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl,
2N/A pcnt);
2N/A for (ai = 0; ai < pcnt; ai++)
2N/A if (apl[ai] != NULL)
2N/A nvlist_free(apl[ai]);
2N/A topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *));
2N/A if (e != 0) {
2N/A nvlist_free(pgnvl);
2N/A return (-1);
2N/A }
2N/A }
2N/A rpad->tpad_pgs[pi] = pgnvl;
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Apgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
2N/A tf_pad_t *rpad, const char *ppgrp)
2N/A{
2N/A xmlNodePtr cn;
2N/A int pi = 0;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: pxn->name=%s\n",
2N/A __func__, pxn->name);
2N/A for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) {
2N/A if (pgroup_record(mp, cn, tn, rname, rpad, pi++, ppgrp)
2N/A < 0)
2N/A return (-1);
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * psn: pointer to a "set" XML node
2N/A * key: string to search the set for
2N/A *
2N/A * returns: 1, if the set contains key
2N/A * 0, otherwise
2N/A */
2N/Astatic int
2N/Aset_contains(topo_mod_t *mp, char *key, char *set)
2N/A{
2N/A char *prod;
2N/A int rv = 0;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: set_contains(key = %s, "
2N/A "setlist = %s)\n", __func__, key, set);
2N/A
2N/A prod = strtok((char *)set, "|");
2N/A if (prod && (strcmp(key, prod) == 0))
2N/A return (1);
2N/A
2N/A while ((prod = strtok(NULL, "|")))
2N/A if (strcmp(key, prod) == 0)
2N/A return (1);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Process the property group and dependents xmlNode children of
2N/A * parent xmlNode pxn.
2N/A */
2N/Astatic int
2N/Apad_process(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
2N/A tf_pad_t **rpad)
2N/A{
2N/A xmlNodePtr cn, gcn, psn, ecn, target;
2N/A xmlNodePtr def_set = NULL;
2N/A tnode_t *ct;
2N/A tf_pad_t *new = *rpad;
2N/A tf_rdata_t tmp_rd;
2N/A int pgcnt = 0;
2N/A int dcnt = 0;
2N/A int ecnt = 0;
2N/A int joined_set = 0, inst;
2N/A xmlChar *set;
2N/A char *key;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: beneath %s=%d\n", __func__, topo_node_name(ptn),
2N/A topo_node_instance(ptn));
2N/A if (new == NULL) {
2N/A for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: cn->name is %s \n",
2N/A __func__, (char *)cn->name);
2N/A /*
2N/A * We're iterating through the XML children looking for
2N/A * four types of elements:
2N/A * 1) dependents elements
2N/A * 2) unconstrained pgroup elements
2N/A * 3) pgroup elements constrained by set elements
2N/A * 4) enum-method elements for the case that we want
2N/A * to post-process a statically defined node
2N/A */
2N/A if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0)
2N/A dcnt++;
2N/A else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0)
2N/A pgcnt++;
2N/A else if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth)
2N/A == 0) {
2N/A ecn = cn;
2N/A ecnt++;
2N/A } else if (xmlStrcmp(cn->name, (xmlChar *)Set) == 0) {
2N/A if (joined_set)
2N/A continue;
2N/A set = xmlGetProp(cn, (xmlChar *)Setlist);
2N/A
2N/A if (mp->tm_hdl->th_product)
2N/A key = mp->tm_hdl->th_product;
2N/A else
2N/A key = mp->tm_hdl->th_platform;
2N/A
2N/A /*
2N/A * If it's the default set then we'll store
2N/A * a pointer to it so that if none of the other
2N/A * sets apply to our product we can fall
2N/A * back to this one.
2N/A */
2N/A if (strcmp((char *)set, "default") == 0)
2N/A def_set = cn;
2N/A else if (set_contains(mp, key, (char *)set)) {
2N/A psn = cn;
2N/A joined_set = 1;
2N/A for (gcn = cn->xmlChildrenNode;
2N/A gcn != NULL; gcn = gcn->next) {
2N/A if (xmlStrcmp(gcn->name,
2N/A (xmlChar *)Propgrp) == 0)
2N/A pgcnt++;
2N/A }
2N/A }
2N/A xmlFree(set);
2N/A }
2N/A }
2N/A /*
2N/A * If we haven't found a set that contains our product AND
2N/A * a default set exists, then we'll process it.
2N/A */
2N/A if (!joined_set && def_set) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: falling back to default set\n", __func__);
2N/A joined_set = 1;
2N/A psn = def_set;
2N/A for (gcn = psn->xmlChildrenNode; gcn != NULL;
2N/A gcn = gcn->next) {
2N/A if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp)
2N/A == 0)
2N/A pgcnt++;
2N/A }
2N/A }
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n",
2N/A __func__, dcnt, pgcnt, ecnt, joined_set);
2N/A /*
2N/A * If an enum-method element was found, AND we're a child of a
2N/A * node element, then we invoke the enumerator so that it can do
2N/A * post-processing of the node.
2N/A */
2N/A if (ecnt && (strcmp((const char *)pxn->name, Node) == 0)) {
2N/A if ((tmp_rd.rd_einfo = enum_attributes_process(mp, ecn))
2N/A == NULL)
2N/A return (-1);
2N/A tmp_rd.rd_mod = mp;
2N/A tmp_rd.rd_name = rd->rd_name;
2N/A tmp_rd.rd_min = rd->rd_min;
2N/A tmp_rd.rd_max = rd->rd_max;
2N/A tmp_rd.rd_pn = ptn;
2N/A if (enum_run(mp, &tmp_rd) < 0) {
2N/A /*
2N/A * Note the failure but continue on
2N/A */
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: enumeration failed\n", __func__);
2N/A }
2N/A tf_edata_free(mp, tmp_rd.rd_einfo);
2N/A }
2N/A /*
2N/A * Here we allocate an element in an intermediate data structure
2N/A * which keeps track property groups and dependents of the range
2N/A * currently being processed.
2N/A *
2N/A * This structure is referenced in pgroups_record() to create
2N/A * the actual property groups in the topo tree
2N/A */
2N/A if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL)
2N/A return (-1);
2N/A
2N/A if (pgcnt > 0) {
2N/A new->tpad_pgs =
2N/A topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *));
2N/A if (new->tpad_pgs == NULL) {
2N/A tf_pad_free(mp, new);
2N/A return (-1);
2N/A }
2N/A }
2N/A /*
2N/A * If the property groups are contained within a set
2N/A * then they will be one level lower in the XML tree.
2N/A */
2N/A if (joined_set)
2N/A target = psn;
2N/A else
2N/A target = pxn;
2N/A
2N/A /*
2N/A * If there is no "node" element under the "range"
2N/A * element, then we need to attach the facility node to
2N/A * each node in this range.
2N/A *
2N/A * Otherwise we only attach it to the current node
2N/A */
2N/A if (xmlStrcmp(target->name, (xmlChar *)Range) == 0 ||
2N/A xmlStrcmp(target->name, (xmlChar *)Set) == 0) {
2N/A for (ct = topo_child_first(rd->rd_pn);
2N/A ct != NULL;
2N/A ct = topo_child_next(rd->rd_pn, ct)) {
2N/A
2N/A if (strcmp(topo_node_name(ct),
2N/A rd->rd_name) != 0)
2N/A continue;
2N/A
2N/A inst = topo_node_instance(ct);
2N/A if (inst < rd->rd_min || inst > rd->rd_max)
2N/A continue;
2N/A
2N/A if (fac_enum_process(mp, target, ct) < 0)
2N/A return (-1);
2N/A
2N/A if (fac_process(mp, target, rd, ct) < 0)
2N/A return (-1);
2N/A }
2N/A } else {
2N/A if (fac_enum_process(mp, target, ptn) < 0)
2N/A return (-1);
2N/A if (fac_process(mp, target, rd, ptn) < 0)
2N/A return (-1);
2N/A }
2N/A if (pgcnt > 0 && pgroups_record(mp, target, ptn, rd->rd_name,
2N/A new, (const char *)pxn->name) < 0) {
2N/A tf_pad_free(mp, new);
2N/A return (-1);
2N/A }
2N/A *rpad = new;
2N/A }
2N/A
2N/A if (new->tpad_dcnt > 0)
2N/A if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0)
2N/A return (-1);
2N/A
2N/A if (new->tpad_pgcnt > 0)
2N/A if (pgroups_create(mp, new, ptn) < 0)
2N/A return (-1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/Astatic int
2N/Afac_enum_process(topo_mod_t *mp, xmlNodePtr pn, tnode_t *ptn)
2N/A{
2N/A xmlNodePtr cn;
2N/A xmlChar *fprov = NULL;
2N/A int rv = 0;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: called for %s=%d\n", __func__, topo_node_name(ptn),
2N/A topo_node_instance(ptn));
2N/A
2N/A for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A
2N/A if (xmlStrcmp(cn->name, (xmlChar *)"fac-enum") != 0)
2N/A continue;
2N/A
2N/A if ((fprov = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
2N/A goto fenumdone;
2N/A
2N/A if (xmlStrcmp(fprov, (xmlChar *)"fac_prov_ipmi") != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: invalid provider specified: %s\n",
2N/A __func__, fprov);
2N/A goto fenumdone;
2N/A }
2N/A
2N/A /*
2N/A * Invoke enum entry point in fac provider which will cause the
2N/A * facility enumeration node method to be registered.
2N/A */
2N/A if (fac_enum_run(mp, ptn, (const char *)fprov) != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: enum entry point failed!\n", __func__);
2N/A goto fenumdone;
2N/A }
2N/A xmlFree(fprov);
2N/A }
2N/A return (0);
2N/Afenumdone:
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: processing failed\n", __func__);
2N/A
2N/A if (fprov != NULL)
2N/A xmlFree(fprov);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A
2N/Astatic int
2N/Afac_process(topo_mod_t *mp, xmlNodePtr pn, tf_rdata_t *rd, tnode_t *ptn)
2N/A{
2N/A xmlNodePtr cn;
2N/A xmlChar *fname = NULL, *ftype = NULL, *provider = NULL;
2N/A tnode_t *ntn = NULL;
2N/A tf_idata_t *newi;
2N/A int err;
2N/A topo_pgroup_info_t pgi;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: called for %s=%d\n", __func__, topo_node_name(ptn),
2N/A topo_node_instance(ptn));
2N/A
2N/A for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A
2N/A if (xmlStrcmp(cn->name, (xmlChar *)Facility) != 0)
2N/A continue;
2N/A
2N/A if ((fname = xmlGetProp(cn, (xmlChar *)Name)) == NULL)
2N/A goto facdone;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: processing facility node '%s'\n", __func__, fname);
2N/A
2N/A if ((ftype = xmlGetProp(cn, (xmlChar *)Type)) == NULL)
2N/A goto facdone;
2N/A
2N/A if ((provider = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
2N/A goto facdone;
2N/A
2N/A if (xmlStrcmp(ftype, (xmlChar *)Sensor) != 0 &&
2N/A xmlStrcmp(ftype, (xmlChar *)Indicator) != 0)
2N/A goto facdone;
2N/A
2N/A if (xmlStrcmp(provider, (xmlChar *)"fac_prov_ipmi") != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: invalid provider attr value: %s\n",
2N/A __func__, provider);
2N/A goto facdone;
2N/A }
2N/A
2N/A if ((ntn = topo_node_facbind(mp, ptn, (char *)fname,
2N/A (char *)ftype)) == NULL)
2N/A goto facdone;
2N/A
2N/A pgi.tpi_name = TOPO_PGROUP_FACILITY;
2N/A pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
2N/A pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
2N/A pgi.tpi_version = 1;
2N/A if (topo_pgroup_create(ntn, &pgi, &err) != 0) {
2N/A if (err != ETOPO_PROP_DEFD) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: pgroups create failure: %s\n",
2N/A __func__, topo_strerror(err));
2N/A return (-1);
2N/A }
2N/A }
2N/A /*
2N/A * Invoke enum entry point in fac_prov_ipmi module, which will
2N/A * cause the provider methods to be registered on this node
2N/A */
2N/A if (fac_enum_run(mp, ntn, (const char *)provider) != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: enum entry point failed for provider %s!\n",
2N/A __func__, provider);
2N/A goto facdone;
2N/A }
2N/A
2N/A if ((newi = tf_idata_new(mp, 0, ntn)) == NULL)
2N/A goto facdone;
2N/A
2N/A if (tf_idata_insert(&rd->rd_instances, newi) < 0)
2N/A goto facdone;
2N/A
2N/A if (pad_process(mp, rd, cn, ntn, &newi->ti_pad) < 0)
2N/A goto facdone;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: done with "
2N/A "facility %s=%s\n", __func__, ftype, fname);
2N/A
2N/A xmlFree(ftype);
2N/A xmlFree(fname);
2N/A xmlFree(provider);
2N/A }
2N/A
2N/A return (0);
2N/A
2N/Afacdone:
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: processing failed\n", __func__);
2N/A
2N/A if (ftype != NULL)
2N/A xmlFree(ftype);
2N/A if (fname != NULL)
2N/A xmlFree(fname);
2N/A if (provider != NULL)
2N/A xmlFree(provider);
2N/A if (ntn != NULL)
2N/A topo_node_unbind(ntn);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Anode_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd)
2N/A{
2N/A xmlChar *str;
2N/A topo_instance_t inst;
2N/A tf_idata_t *newi;
2N/A tnode_t *ntn;
2N/A uint64_t ui;
2N/A int rv = -1;
2N/A int s = 0;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: mod=%s, name=%s\n", __func__, mp->tm_name, rd->rd_name);
2N/A
2N/A if (xmlattr_to_int(mp, nn, Instance, &ui) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: xmlattr_to_int() failed\n", __func__);
2N/A goto nodedone;
2N/A }
2N/A inst = (topo_instance_t)ui;
2N/A
2N/A if ((str = xmlGetProp(nn, (xmlChar *)Static)) != NULL) {
2N/A if (xmlStrcmp(str, (xmlChar *)True) == 0)
2N/A s = 1;
2N/A xmlFree(str);
2N/A }
2N/A
2N/A /*
2N/A * We must call this for "Static" nodes as well since
2N/A * xml snapshots have everything defined as such.
2N/A */
2N/A if (topo_mod_enumerate(rd->rd_mod, rd->rd_pn,
2N/A rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst, NULL) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: topo_mod_enumerate() failed\n", __func__);
2N/A goto nodedone;
2N/A }
2N/A ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst);
2N/A
2N/A if (ntn == NULL) {
2N/A
2N/A /*
2N/A * If this is a static node declaration, we can
2N/A * ignore the lookup failure and continue
2N/A * processing. Otherwise, something
2N/A * went wrong during enumeration
2N/A */
2N/A if (s == 1)
2N/A rv = 0;
2N/A goto nodedone;
2N/A }
2N/A if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: tf_idata_new() failed\n", __func__);
2N/A goto nodedone;
2N/A }
2N/A if (tf_idata_insert(&rd->rd_instances, newi) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: tf_idata_insert() failed\n", __func__);
2N/A goto nodedone;
2N/A }
2N/A if (pad_process(mp, rd, nn, ntn, &newi->ti_pad) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: pad_process() failed\n", __func__);
2N/A goto nodedone;
2N/A }
2N/A if (fac_process(mp, nn, rd, ntn) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: fac_process() failed\n", __func__);
2N/A goto nodedone;
2N/A }
2N/A rv = 0;
2N/Anodedone:
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: done with node %s\n",
2N/A __func__, rd->rd_name);
2N/A
2N/A if (rv < 0)
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: returning error, rv=%d\n", __func__, rv);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/Astatic tf_edata_t *
2N/Aenum_attributes_process(topo_mod_t *mp, xmlNodePtr en)
2N/A{
2N/A tf_edata_t *einfo;
2N/A uint64_t ui;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s:\n", __func__);
2N/A if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) {
2N/A (void) topo_mod_seterrno(mp, ETOPO_NOMEM);
2N/A return (NULL);
2N/A }
2N/A einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name);
2N/A if (einfo->te_name == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: enumerator name attribute missing\n", __func__);
2N/A (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
2N/A goto enodedone;
2N/A }
2N/A
2N/A /*
2N/A * Check for recursive enumeration
2N/A */
2N/A if (strcmp(einfo->te_name, mp->tm_name) == 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: recursive enumeration detected for %s\n", __func__,
2N/A einfo->te_name);
2N/A (void) topo_mod_seterrno(mp, ETOPO_ENUM_RECURS);
2N/A goto enodedone;
2N/A }
2N/A if (xmlattr_to_int(mp, en, Version, &ui) < 0)
2N/A goto enodedone;
2N/A einfo->te_vers = (int)ui;
2N/A
2N/A return (einfo);
2N/A
2N/Aenodedone:
2N/A if (einfo->te_name != NULL)
2N/A xmlFree(einfo->te_name);
2N/A topo_mod_free(mp, einfo, sizeof (tf_edata_t));
2N/A return (NULL);
2N/A}
2N/A
2N/Astatic int
2N/Aenum_run(topo_mod_t *mp, tf_rdata_t *rd)
2N/A{
2N/A topo_hdl_t *thp = mp->tm_hdl;
2N/A int e = -1;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s:\n", __func__);
2N/A
2N/A /*
2N/A * Check if the enumerator module is already loaded.
2N/A * Module loading is single-threaded at this point so there's
2N/A * no need to worry about the module going away or bumping the
2N/A * ref count.
2N/A */
2N/A if ((rd->rd_mod = topo_mod_lookup(thp, rd->rd_einfo->te_name,
2N/A 0)) == NULL) {
2N/A if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name,
2N/A rd->rd_einfo->te_vers)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: mod_load of %s failed: %s\n", __func__,
2N/A rd->rd_einfo->te_name,
2N/A topo_strerror(topo_mod_errno(mp)));
2N/A (void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
2N/A return (e);
2N/A }
2N/A }
2N/A /*
2N/A * We're live, so let's enumerate.
2N/A */
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: enumerate request. (%s)\n",
2N/A __func__, rd->rd_einfo->te_name);
2N/A e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name,
2N/A rd->rd_name, rd->rd_min, rd->rd_max, NULL);
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: back from enumeration. "
2N/A "%d\n", __func__, e);
2N/A if (e != 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: enumeration failed (%s)\n", __func__,
2N/A topo_strerror(topo_mod_errno(mp)));
2N/A (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
2N/A return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
2N/A }
2N/A return (e);
2N/A}
2N/A
2N/Astatic int
2N/Afac_enum_run(topo_mod_t *mp, tnode_t *node, const char *name)
2N/A{
2N/A topo_hdl_t *thp = mp->tm_hdl;
2N/A topo_mod_t *fmod;
2N/A int e = -1;
2N/A
2N/A topo_dprintf(thp, TOPO_DBG_XML, "%s:\n", __func__);
2N/A /*
2N/A * Check if the enumerator module is already loaded.
2N/A * Module loading is single-threaded at this point so there's
2N/A * no need to worry about the module going away or bumping the
2N/A * ref count.
2N/A */
2N/A if ((fmod = topo_mod_lookup(thp, name, 0)) == NULL) {
2N/A if ((fmod = topo_mod_load(mp, name, TOPO_VERSION)) == NULL) {
2N/A topo_dprintf(thp, TOPO_DBG_ERR,
2N/A "%s: mod_load of %s failed: %s\n", __func__,
2N/A name, topo_strerror(topo_mod_errno(mp)));
2N/A (void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
2N/A return (e);
2N/A }
2N/A }
2N/A /*
2N/A * We're live, so let's enumerate.
2N/A */
2N/A topo_dprintf(thp, TOPO_DBG_XML, "%s: fac enumerate request. (%s)\n",
2N/A __func__, name);
2N/A e = topo_mod_enumerate(fmod, node, name, name, 0, 0, NULL);
2N/A topo_dprintf(thp, TOPO_DBG_XML, "%s: back from enumeration. %d\n",
2N/A __func__, e);
2N/A if (e != 0) {
2N/A topo_dprintf(thp, TOPO_DBG_ERR,
2N/A "%s: acility provider enumeration failed (%s)\n", __func__,
2N/A topo_strerror(topo_mod_errno(mp)));
2N/A (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
2N/A return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
2N/A }
2N/A return (e);
2N/A}
2N/A
2N/Aint
2N/Adecorate_nodes(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
2N/A tf_pad_t **rpad)
2N/A{
2N/A tnode_t *ctn;
2N/A
2N/A ctn = topo_child_first(ptn);
2N/A while (ctn != NULL) {
2N/A /* Only care about instances within the range */
2N/A if (strcmp(topo_node_name(ctn), rd->rd_name) != 0) {
2N/A ctn = topo_child_next(ptn, ctn);
2N/A continue;
2N/A }
2N/A if (pad_process(mp, rd, pxn, ctn, rpad) < 0)
2N/A return (-1);
2N/A if (decorate_nodes(mp, rd, pxn, ctn, rpad) < 0)
2N/A return (-1);
2N/A ctn = topo_child_next(ptn, ctn);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Atopo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
2N/A{
2N/A /*
2N/A * The range may have several children xmlNodes, that may
2N/A * represent the enumeration method, property groups,
2N/A * dependents, nodes or services.
2N/A */
2N/A xmlNodePtr cn, enum_node = NULL, pmap_node = NULL;
2N/A xmlChar *pmap_name;
2N/A tnode_t *ct;
2N/A int e, ccnt = 0;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: process %s range beneath %s\n", __func__, rd->rd_name,
2N/A topo_node_name(rd->rd_pn));
2N/A
2N/A e = topo_node_range_create(mp,
2N/A rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max);
2N/A if (e != 0 && topo_mod_errno(mp) != EMOD_NODE_DUP) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: range create failed due to %s\n", __func__,
2N/A topo_strerror(topo_mod_errno(mp)));
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Before we process any of the other child xmlNodes, we iterate through
2N/A * the children and looking for either enum-method or propmap elements.
2N/A */
2N/A for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next)
2N/A if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0)
2N/A enum_node = cn;
2N/A else if (xmlStrcmp(cn->name, (xmlChar *)Propmap) == 0)
2N/A pmap_node = cn;
2N/A
2N/A /*
2N/A * If we found an enum-method element, process it first
2N/A */
2N/A if (enum_node != NULL) {
2N/A if ((rd->rd_einfo = enum_attributes_process(mp, enum_node))
2N/A == NULL)
2N/A return (-1);
2N/A if (enum_run(mp, rd) < 0) {
2N/A /*
2N/A * Note the failure but continue on
2N/A */
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: enumeration failed\n", __func__);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Next, check if a propmap element was found and if so, load it in
2N/A * and parse it.
2N/A */
2N/A if (pmap_node != NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: found a propmap "
2N/A "element\n", __func__);
2N/A if ((pmap_name = xmlGetProp(pmap_node, (xmlChar *)Name))
2N/A == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: propmap element missing name attribute\n",
2N/A __func__);
2N/A } else {
2N/A if (topo_file_load(mp, rd->rd_pn,
2N/A (const char *)pmap_name, rd->rd_finfo->tf_scheme,
2N/A B_TRUE) < 0) {
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: topo_file_load failed: %s\n",
2N/A __func__,
2N/A topo_strerror(topo_mod_errno(mp)));
2N/A }
2N/A xmlFree(pmap_name);
2N/A }
2N/A }
2N/A
2N/A /* Now look for nodes, i.e., hard instances */
2N/A for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) {
2N/A if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) {
2N/A if (node_process(mp, cn, rd) < 0) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: node processing failed: %s\n",
2N/A __func__,
2N/A topo_strerror(topo_mod_errno(mp)));
2N/A return (topo_mod_seterrno(mp,
2N/A EMOD_PARTIAL_ENUM));
2N/A }
2N/A ccnt++;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Finally, process the property groups and dependents
2N/A *
2N/A * If the TF_PROPMAP flag is set for the XML file we're currently
2N/A * processing, then this XML file was loaded via propmap. In that case
2N/A * we call a special routine to recursively apply the propgroup settings
2N/A * to all of nodes in this range
2N/A */
2N/A if (rd->rd_finfo->tf_flags & TF_PROPMAP)
2N/A (void) decorate_nodes(mp, rd, rn, rd->rd_pn, &rd->rd_pad);
2N/A else {
2N/A ct = topo_child_first(rd->rd_pn);
2N/A while (ct != NULL) {
2N/A /* Only care about instances within the range */
2N/A if (strcmp(topo_node_name(ct), rd->rd_name) != 0) {
2N/A ct = topo_child_next(rd->rd_pn, ct);
2N/A continue;
2N/A }
2N/A if (pad_process(mp, rd, rn, ct, &rd->rd_pad)
2N/A < 0)
2N/A return (-1);
2N/A
2N/A if (fac_process(mp, rn, rd, ct) < 0)
2N/A return (-1);
2N/A
2N/A ct = topo_child_next(rd->rd_pn, ct);
2N/A ccnt++;
2N/A }
2N/A }
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s: end range process %s\n",
2N/A __func__, rd->rd_name);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic tf_rdata_t *
2N/Atopo_xml_walk(topo_mod_t *mp,
2N/A tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot)
2N/A{
2N/A xmlNodePtr curr, def_set = NULL;
2N/A tf_rdata_t *rr, *pr, *rdp;
2N/A xmlChar *set;
2N/A char *key;
2N/A int joined_set = 0;
2N/A
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "%s:\n", __func__);
2N/A rr = pr = NULL;
2N/A /*
2N/A * First iterate through all the XML nodes at this level to look for
2N/A * set nodes.
2N/A */
2N/A for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
2N/A if (curr->name == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: Ignoring nameless xmlnode\n", __func__);
2N/A continue;
2N/A }
2N/A if (xmlStrcmp(curr->name, (xmlChar *)Set) == 0) {
2N/A if (joined_set)
2N/A continue;
2N/A
2N/A set = xmlGetProp(curr, (xmlChar *)Setlist);
2N/A
2N/A if (mp->tm_hdl->th_product)
2N/A key = mp->tm_hdl->th_product;
2N/A else
2N/A key = mp->tm_hdl->th_platform;
2N/A
2N/A /*
2N/A * If it's the default set then we'll store
2N/A * a pointer to it so that if none of the other
2N/A * sets apply to our product we can fall
2N/A * back to this one.
2N/A */
2N/A if (strcmp((char *)set, "default") == 0)
2N/A def_set = curr;
2N/A else if (set_contains(mp, key, (char *)set)) {
2N/A joined_set = 1;
2N/A if ((rdp = topo_xml_walk(mp, xinfo, curr,
2N/A troot)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: failed1\n", __func__);
2N/A } else {
2N/A if (pr == NULL) {
2N/A rr = pr = rdp;
2N/A } else {
2N/A pr->rd_next = rdp;
2N/A pr = rdp;
2N/A }
2N/A rr->rd_cnt++;
2N/A }
2N/A }
2N/A xmlFree(set);
2N/A }
2N/A }
2N/A /*
2N/A * If we haven't found a set that contains our product AND a default set
2N/A * exists, then we'll process it.
2N/A */
2N/A if (!joined_set && def_set) {
2N/A if ((rdp = topo_xml_walk(mp, xinfo, def_set, troot)) == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: failed2\n", __func__);
2N/A }
2N/A if (pr == NULL) {
2N/A rr = pr = rdp;
2N/A } else {
2N/A pr->rd_next = rdp;
2N/A pr = rdp;
2N/A }
2N/A rr->rd_cnt++;
2N/A }
2N/A /*
2N/A * Now we're interested in children xmlNodes of croot tagged
2N/A * as 'ranges'. These define what topology nodes may exist, and need
2N/A * to be verified.
2N/A */
2N/A for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
2N/A if (curr->name == NULL) {
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: Ignoring nameless xmlnode\n", __func__);
2N/A continue;
2N/A }
2N/A if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0)
2N/A continue;
2N/A if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) {
2N/A /*
2N/A * Range processing error, continue walk
2N/A */
2N/A topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
2N/A "%s: range processing error, errmsg=%s\n",
2N/A __func__, topo_mod_errmsg(mp));
2N/A continue;
2N/A }
2N/A if (pr == NULL) {
2N/A rr = pr = rdp;
2N/A } else {
2N/A pr->rd_next = rdp;
2N/A pr = rdp;
2N/A }
2N/A rr->rd_cnt++;
2N/A }
2N/A
2N/A return (rr);
2N/A}
2N/A
2N/A/*
2N/A * Convert parsed xml topology description into topology nodes
2N/A */
2N/Aint
2N/Atopo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot)
2N/A{
2N/A xmlNodePtr xroot;
2N/A
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "%s:\n", __func__);
2N/A
2N/A if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: couldn't get root xmlNode\n", __func__);
2N/A return (-1);
2N/A }
2N/A if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: error within .xml topology: %s\n", __func__,
2N/A topo_strerror(topo_mod_errno(tmp)));
2N/A return (-1);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A#define MFG 0
2N/A#define NAME 1
2N/A#define PART 2
2N/A#define SERIAL 3
2N/A
2N/A#define MAX_AUTH_TYPES 3
2N/A#define MAX_AUTHS 4
2N/A/*
2N/A * Parse the high level authority information placing it into the
2N/A * authority nvlist.
2N/A */
2N/Astatic void
2N/Atxml_parse_auth(topo_mod_t *tmp, xmlNodePtr cursor)
2N/A{
2N/A int i;
2N/A xmlChar *mfg = NULL;
2N/A xmlChar *name = NULL;
2N/A xmlChar *part = NULL;
2N/A xmlChar *serial = NULL;
2N/A nvlist_t *nvl;
2N/A int auth_types[MAX_AUTH_TYPES] = {
2N/A FM_FMRI_AUTH_TYPE_SYSTEM, /* System */
2N/A FM_FMRI_AUTH_TYPE_SYS_COMP, /* Component Systeem */
2N/A FM_FMRI_AUTH_TYPE_CHASSIS /* Chassis */
2N/A };
2N/A const char *auths[MAX_AUTH_TYPES][MAX_AUTHS] = {
2N/A { FM_FMRI_AUTH_V1_SYSTEM_MFG, /* Manufacturer */
2N/A FM_FMRI_AUTH_V1_SYSTEM_NM, /* Name */
2N/A FM_FMRI_AUTH_V1_SYSTEM_PN, /* Part Number */
2N/A FM_FMRI_AUTH_V1_SYSTEM_SN }, /* Serial Number */
2N/A { FM_FMRI_AUTH_V1_SYS_COMP_MFG,
2N/A FM_FMRI_AUTH_V1_SYS_COMP_NM,
2N/A FM_FMRI_AUTH_V1_SYS_COMP_PN,
2N/A FM_FMRI_AUTH_V1_SYS_COMP_SN },
2N/A { FM_FMRI_AUTH_V1_CHASSIS_MFG,
2N/A FM_FMRI_AUTH_V1_CHASSIS_NM,
2N/A FM_FMRI_AUTH_V1_CHASSIS_PN,
2N/A FM_FMRI_AUTH_V1_CHASSIS_SN }
2N/A };
2N/A
2N/A /* alloc authority nvlist */
2N/A if (topo_mod_nvalloc(tmp, &nvl, NV_UNIQUE_NAME) != 0) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML | TOPO_DBG_SNAP,
2N/A "%s: failed to alloc authority nvlist\n", __func__);
2N/A return;
2N/A }
2N/A
2N/A /* fill in authority nvlist */
2N/A for (i = 0; i < MAX_AUTH_TYPES; i++) {
2N/A mfg = xmlGetProp(cursor, (xmlChar *)auths[i][MFG]);
2N/A name = xmlGetProp(cursor, (xmlChar *)auths[i][NAME]);
2N/A part = xmlGetProp(cursor, (xmlChar *)auths[i][PART]);
2N/A serial = xmlGetProp(cursor, (xmlChar *)auths[i][SERIAL]);
2N/A
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML | TOPO_DBG_SNAP,
2N/A "%s: %s mfg(%s) name(%s) part(%s) serial(%s)\n", __func__,
2N/A i == FM_FMRI_AUTH_TYPE_SYSTEM ? "system" :
2N/A i == FM_FMRI_AUTH_TYPE_SYS_COMP ? "component system" :
2N/A "chassis", mfg, name, part, serial);
2N/A
2N/A /* add to nvlist */
2N/A topo_mod_auth_set_nvl(tmp, &nvl, auth_types[i],
2N/A (char *)mfg, (char *)name, (char *)part, (char *)serial);
2N/A
2N/A xmlFree(mfg);
2N/A xmlFree(name);
2N/A xmlFree(part);
2N/A xmlFree(serial);
2N/A }
2N/A
2N/A /* set auth nvl to topo handle */
2N/A topo_mod_auth_set_th(tmp, nvl);
2N/A nvlist_free(nvl);
2N/A
2N/A}
2N/A
2N/A/*
2N/A * Load an XML tree from filename and read it into a DOM parse tree.
2N/A */
2N/Astatic tf_info_t *
2N/Atxml_file_parse(topo_mod_t *tmp,
2N/A int fd, const char *filenm, const char *escheme)
2N/A{
2N/A xmlValidCtxtPtr vcp;
2N/A xmlNodePtr cursor;
2N/A xmlDocPtr document;
2N/A xmlDtdPtr dtd = NULL;
2N/A xmlChar *scheme = NULL;
2N/A xmlChar *uuid = NULL;
2N/A xmlChar *timestamp = NULL;
2N/A topo_hdl_t *thp = tmp->tm_hdl;
2N/A char *dtdpath = NULL;
2N/A int readflags = 0;
2N/A tf_info_t *r;
2N/A int e, validate = 0;
2N/A boolean_t load_snapshot;
2N/A
2N/A load_snapshot = ((thp->th_snap_dir == NULL) ? B_FALSE : B_TRUE);
2N/A
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML | TOPO_DBG_SNAP,
2N/A "%s: tmp=0x%p, thp=0x%p, filenm=%s, escheme=%s, "
2N/A "load_snapshot=%s\n", __func__, (void *)tmp, (void *)thp,
2N/A (char *)filenm, (char *)escheme,
2N/A (load_snapshot == B_TRUE) ? "TRUE" : "FALSE");
2N/A
2N/A /*
2N/A * Since topologies can XInclude other topologies, and libxml2
2N/A * doesn't do DTD-based validation with XInclude, by default
2N/A * we don't validate topology files. One can force
2N/A * validation, though, by creating a TOPOXML_VALIDATE
2N/A * environment variable and creating a TOPO_DTD environment
2N/A * variable with the path to the DTD against which to validate.
2N/A */
2N/A if (getenv("TOPOXML_VALIDATE") != NULL) {
2N/A dtdpath = getenv("TOPO_DTD");
2N/A if (dtdpath != NULL)
2N/A xmlLoadExtDtdDefaultValue = 0;
2N/A validate = 1;
2N/A }
2N/A
2N/A /*
2N/A * Splat warnings and errors related to parsing the topology
2N/A * file if the TOPOXML_PERROR environment variable exists.
2N/A */
2N/A if (getenv("TOPOXML_PERROR") == NULL)
2N/A readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
2N/A
2N/A if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: couldn't parse document\n", __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_MOD_XRD);
2N/A return (NULL);
2N/A }
2N/A
2N/A /*
2N/A * Verify that this is a document type we understand.
2N/A */
2N/A if ((dtd = xmlGetIntSubset(document)) == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: document has no DTD\n", __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_MOD_XRD);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A
2N/A if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: document DTD unknown; bad topology file\n", __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_MOD_XRD);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((cursor = xmlDocGetRootElement(document)) == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: document is empty\n", __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_MOD_XRD);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A
2N/A /*
2N/A * Make sure we're looking at a topology description in the
2N/A * expected scheme.
2N/A */
2N/A if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: document is not a topology description\n", __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_MOD_XRD);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: topology lacks a scheme\n", __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: topology in unrecognized scheme, %s, expecting %s\n",
2N/A __func__, scheme, escheme);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH);
2N/A xmlFree(scheme);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A /*
2N/A * If we're loading a snapshot file,
2N/A * then we expect a UUID and timestamp to be present.
2N/A */
2N/A if (load_snapshot == B_TRUE) {
2N/A /*
2N/A * Lookup UUID.
2N/A */
2N/A if ((uuid = xmlGetProp(cursor, (xmlChar *)UUID)) == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR | TOPO_DBG_SNAP,
2N/A "%s: topology snapshot is missing a UUID\n",
2N/A __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR);
2N/A xmlFree(scheme);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A if ((thp->th_uuid = topo_hdl_zalloc(thp,
2N/A TOPO_UUID_SIZE)) == NULL) {
2N/A topo_dprintf(thp, TOPO_DBG_ERR, "%s: unable "
2N/A "to allocate uuid\n", __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_NOMEM);
2N/A xmlFree(uuid);
2N/A xmlFree(scheme);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A (void) strncpy(thp->th_uuid, (char *)uuid, TOPO_UUID_SIZE);
2N/A topo_dprintf(thp, TOPO_DBG_ERR, "%s: th_uuid=0x%p(%s)\n",
2N/A __func__, (void *)thp->th_uuid, thp->th_uuid);
2N/A xmlFree(uuid);
2N/A
2N/A /*
2N/A * Lookup timestamp.
2N/A */
2N/A if ((timestamp = xmlGetProp(cursor, (xmlChar *)Timestamp))
2N/A == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR | TOPO_DBG_SNAP,
2N/A "%s: topology snapshot is missing a timestamp\n",
2N/A __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR);
2N/A xmlFree(scheme);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A topo_dprintf(thp, TOPO_DBG_SNAP, "%s: timestamp=%s\n",
2N/A __func__, timestamp);
2N/A thp->th_timestamp = strtoul((char *)timestamp, NULL, 0);
2N/A topo_dprintf(thp, TOPO_DBG_SNAP, "%s: snapshot th_uuid=%s, "
2N/A "timestamp=0x%lx=%s=%s\n", __func__, thp->th_uuid,
2N/A (ulong_t)thp->th_timestamp, timestamp,
2N/A ctime(&thp->th_timestamp));
2N/A xmlFree(timestamp);
2N/A
2N/A /* authority */
2N/A txml_parse_auth(tmp, cursor);
2N/A }
2N/A
2N/A if (dtdpath != NULL) {
2N/A dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
2N/A if (dtd == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: could not parse DTD \"%s\"\n",
2N/A __func__, dtdpath);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_MOD_XRD);
2N/A xmlFree(scheme);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A
2N/A if (document->extSubset != NULL)
2N/A xmlFreeDtd(document->extSubset);
2N/A
2N/A document->extSubset = dtd;
2N/A }
2N/A
2N/A if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
2N/A xmlFree(scheme);
2N/A xmlFreeDoc(document);
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: couldn't handle XInclude statements in "
2N/A "document\n", __func__);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_MOD_XRD);
2N/A return (NULL);
2N/A }
2N/A
2N/A if (validate) {
2N/A if ((vcp = xmlNewValidCtxt()) == NULL) {
2N/A (void) topo_mod_seterrno(tmp, ETOPO_MOD_XRD);
2N/A xmlFree(scheme);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A vcp->warning = xmlParserValidityWarning;
2N/A vcp->error = xmlParserValidityError;
2N/A
2N/A e = xmlValidateDocument(vcp, document);
2N/A
2N/A xmlFreeValidCtxt(vcp);
2N/A
2N/A if (e == 0)
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: document is not valid\n", __func__);
2N/A }
2N/A
2N/A if ((r = tf_info_new(tmp, document, scheme)) == NULL) {
2N/A xmlFree(scheme);
2N/A xmlFreeDoc(document);
2N/A return (NULL);
2N/A }
2N/A
2N/A xmlFree(scheme);
2N/A scheme = NULL;
2N/A return (r);
2N/A}
2N/A
2N/Atf_info_t *
2N/Atopo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme)
2N/A{
2N/A int fd;
2N/A tf_info_t *tip;
2N/A
2N/A if ((fd = open(path, O_RDONLY)) < 0) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2N/A "%s: failed to open file %s\n", __func__, path);
2N/A (void) topo_mod_seterrno(tmp, ETOPO_MOD_XRD);
2N/A return (NULL);
2N/A }
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "%s: opened file %s\n",
2N/A __func__, path);
2N/A if ((tip = txml_file_parse(tmp, fd, path, escheme)) == NULL) {
2N/A topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "%s: failed to "
2N/A "parse file %s\n", __func__, path);
2N/A }
2N/A (void) close(fd);
2N/A return (tip);
2N/A}