Mercurial > illumos > illumos-gate
changeset 4087:b986877655d2
6521594 fmtopo '[-Cdev]' usage doesn't make sense
6534608 libtopo walkers could be smarter
6534610 libtopo: need mechanism to call plugin methods to get/set properties
6537307 fmri_prop() is broken for anything but ASRU/FRU
6537759 fmtopo should have a way to execute is_present/is_unusable methods
6542241 fmtopo should support per-FMRI command line options
6545662 libtopo needs to be robust in the face of memory allocation failure
6547235 bad argument used to call TOPO_METH_CONTAINS in topo_fmri_contains
6547427 hc.c topo enumerator is riddled with potential SEGVs
6548245 Mucho memory leaks in XML parser error code paths
line wrap: on
line diff
--- a/usr/src/cmd/fm/fmtopo/common/fmtopo.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/cmd/fm/fmtopo/common/fmtopo.c Mon Apr 23 15:34:38 2007 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,10 +29,12 @@ #include <sys/fm/protocol.h> #include <fm/libtopo.h> #include <ctype.h> +#include <fnmatch.h> #include <limits.h> #include <strings.h> #include <stdio.h> #include <errno.h> +#include <umem.h> #include <sys/param.h> #define FMTOPO_EXIT_SUCCESS 0 @@ -44,63 +46,88 @@ #define ALL "all" static const char *g_pname; +static const char *g_fmri = NULL; static const char *opt_R = "/"; -static const char *opt_P = NULL; static const char *opt_s = FM_FMRI_SCHEME_HC; +static const char optstr[] = "aCdeP:pR:s:StvVx"; static int opt_e = 0; static int opt_d = 0; static int opt_V = 0; static int opt_p = 0; +static int opt_S = 0; +static int opt_t = 0; static int opt_x = 0; +static int opt_all = 0; + +struct prop_args { + const char *group; + const char *prop; + const char *type; + const char *value; +}; + +static struct prop_args **pargs = NULL; +static int pcnt = 0; static int usage(FILE *fp) { (void) fprintf(fp, - "Usage: %s [-edpvVx] [-Cdev] [-P properties] [-R root] " - "[-s scheme]\n", g_pname); + "Usage: %s [-CedpSVx] [-P group.property[=type:value]] " + "[-R root] [-s scheme] [fmri]\n", g_pname); (void) fprintf(fp, "\t-C dump core after completing execution\n" "\t-d set debug mode for libtopo modules\n" "\t-e display FMRIs as paths using esc/eft notation\n" - "\t-P display of FMRI with the specified properties\n" + "\t-P get/set specified properties\n" "\t-p display of FMRI protocol properties\n" "\t-R set root directory for libtopo plug-ins and other files\n" "\t-s display topology for the specified FMRI scheme\n" + "\t-S display FMRI status (present/usable)\n" "\t-V set verbose mode\n" "\t-x display a xml formatted topology\n"); return (FMTOPO_EXIT_USAGE); } -static void -print_fmri(topo_hdl_t *thp, tnode_t *node) +static topo_type_t +str2type(const char *tstr) { - int err; - char *name; - nvlist_t *fmri; + topo_type_t type; + + if (tstr == NULL) + return (TOPO_TYPE_INVALID); - if (topo_node_resource(node, &fmri, &err) < 0) { - (void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n", - g_pname, topo_node_name(node), - topo_node_instance(node), topo_strerror(err)); - return; + if (strcmp(tstr, "int32") == 0) + type = TOPO_TYPE_INT32; + else if (strcmp(tstr, "uint32") == 0) + type = TOPO_TYPE_UINT32; + else if (strcmp(tstr, "int64") == 0) + type = TOPO_TYPE_INT64; + else if (strcmp(tstr, "uint64") == 0) + type = TOPO_TYPE_UINT64; + else if (strcmp(tstr, "string") == 0) + type = TOPO_TYPE_STRING; + else if (strcmp(tstr, "fmri") == 0) + type = TOPO_TYPE_FMRI; + else { + type = TOPO_TYPE_INVALID; } - if (topo_fmri_nvl2str(thp, fmri, &name, &err) < 0) { - (void) fprintf(stderr, "%s: failed to convert fmri for %s=%d " - "to a string: %s\n", g_pname, topo_node_name(node), - topo_node_instance(node), topo_strerror(err)); - nvlist_free(fmri); - return; - } + return (type); +} - (void) printf("%s\n", name); +static void +print_node(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl, const char *fmri) +{ + int err, ret; - if (opt_p) { + (void) printf("%s\n", (char *)fmri); + + if (opt_p && !(pcnt > 0 || opt_V || opt_all)) { char *aname = NULL, *fname = NULL, *lname = NULL; nvlist_t *asru = NULL; nvlist_t *fru = NULL; @@ -131,9 +158,20 @@ (void) printf("\tLabel: -\n"); } } - nvlist_free(fmri); - topo_hdl_strfree(thp, name); + if (opt_S) { + if ((ret = topo_fmri_present(thp, nvl, &err)) < 0) + (void) printf("\tPresent: -\n"); + else + (void) printf("\tPresent: %s\n", + ret ? "true" : "false"); + + if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0) + (void) printf("\tUnusable: -\n"); + else + (void) printf("\tUnusable: %s\n", + ret ? "true" : "false"); + } } static void @@ -191,7 +229,7 @@ } static void -print_prop_nameval(topo_hdl_t *thp, nvlist_t *nvl, int skip) +print_prop_nameval(topo_hdl_t *thp, nvlist_t *nvl) { int err; topo_type_t type; @@ -217,12 +255,12 @@ if ((pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL || nvpair_name(pv_nvp) == NULL || strcmp(nvpair_name(pv_nvp), TOPO_PROP_VAL_TYPE) != 0 || - nvpair_type(pv_nvp) != DATA_TYPE_INT32) { + nvpair_type(pv_nvp) != DATA_TYPE_UINT32) { (void) fprintf(stderr, "%s: malformed property type for %s\n", g_pname, propn); return; } else { - (void) nvpair_value_int32(pv_nvp, (int32_t *)&type); + (void) nvpair_value_uint32(pv_nvp, (uint32_t *)&type); } switch (type) { @@ -242,8 +280,7 @@ default: tstr = "unknown type"; } - if (!skip) - printf(" %-17s %-8s ", propn, tstr); + printf(" %-17s %-8s ", propn, tstr); /* * Get property value @@ -255,9 +292,6 @@ return; } - if (skip) - return; - switch (nvpair_type(pv_nvp)) { case DATA_TYPE_INT32: { int32_t val; @@ -334,14 +368,27 @@ } static void -print_pgroup(char *pgn, char *dstab, char *nstab, int32_t version, int skip) +print_pgroup(topo_hdl_t *thp, tnode_t *node, const char *pgn, char *dstab, + char *nstab, int32_t version) { + int err; char buf[30]; + topo_pgroup_info_t *pgi = NULL; - if (skip) + if (pgn == NULL) return; - if (!opt_V && strlen(pgn) > 30) { + if (node != NULL && (dstab == NULL || nstab == NULL || version == -1)) { + if ((pgi = topo_pgroup_info(node, pgn, &err)) != NULL) { + dstab = (char *)topo_stability2name(pgi->tpi_datastab); + nstab = (char *)topo_stability2name(pgi->tpi_namestab); + version = pgi->tpi_version; + } + } + + if (dstab == NULL || nstab == NULL || version == -1) { + printf(" group: %-30s version: - stability: -/-\n", pgn); + } else if (!opt_V && strlen(pgn) > 30) { (void) snprintf(buf, 26, "%s", pgn); (void) snprintf(&buf[27], 4, "%s", DOTS); printf(" group: %-30s version: %-3d stability: %s/%s\n", @@ -350,70 +397,22 @@ printf(" group: %-30s version: %-3d stability: %s/%s\n", pgn, version, nstab, dstab); } -} -static int -cmp_name(const char *props, char *pgn) -{ - char buf[MAXNAMELEN]; - size_t count; - char *begin, *end, *value, *next; - char *np; - - if (props == NULL) - return (0); - - if (strcmp(props, ALL) == 0) - return (0); - - - value = np = strdup(props); - - for (end = np; *end != '\0'; value = next) { - end = strchr(value, ','); - if (end != NULL) - next = end + 1; /* skip the comma */ - else - next = end = value + strlen(value); - - /* - * Eat up white space at beginning or end of the - * property group name - */ - begin = value; - while (begin < end && isspace(*begin)) - begin++; - while (begin < end && isspace(*(end - 1))) - end--; - - if (begin >= end) - return (1); - - count = end - begin; - count += 1; - - if (count > sizeof (buf)) - return (1); - - (void) snprintf(buf, count, "%s", begin); - if (strcmp(pgn, buf) == 0) { - free(np); - return (0); - } + if (pgi != NULL) { + topo_hdl_strfree(thp, (char *)pgi->tpi_name); + topo_hdl_free(thp, pgi, sizeof (topo_pgroup_info_t)); } - - free(np); - return (1); } static void -print_props(topo_hdl_t *thp, nvlist_t *p_nv, const char *props) +print_all_props(topo_hdl_t *thp, tnode_t *node, nvlist_t *p_nv, + const char *group) { char *pgn = NULL, *dstab = NULL, *nstab = NULL; - int32_t version = 0; + int32_t version; nvlist_t *pg_nv, *pv_nv; nvpair_t *nvp, *pg_nvp; - int pg_done = 0, skip = 0; + int pg_done, match, all = strcmp(group, ALL) == 0; for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL; nvp = nvlist_next_nvpair(p_nv, nvp)) { @@ -421,6 +420,10 @@ nvpair_type(nvp) != DATA_TYPE_NVLIST) continue; + nstab = NULL; + dstab = NULL; + version = -1; + pg_done = match = 0; (void) nvpair_value_nvlist(nvp, &pg_nv); for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL; pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) { @@ -430,70 +433,325 @@ if (strcmp(TOPO_PROP_GROUP_NAME, nvpair_name(pg_nvp)) == 0 && nvpair_type(pg_nvp) == DATA_TYPE_STRING) { (void) nvpair_value_string(pg_nvp, &pgn); + match = strcmp(group, pgn) == 0; + continue; + } - skip = cmp_name(props, pgn); - - } else if (strcmp(TOPO_PROP_GROUP_NSTAB, + if (strcmp(TOPO_PROP_GROUP_NSTAB, nvpair_name(pg_nvp)) == 0 && nvpair_type(pg_nvp) == DATA_TYPE_STRING) { (void) nvpair_value_string(pg_nvp, &nstab); - } else if (strcmp(TOPO_PROP_GROUP_DSTAB, + continue; + } + + if (strcmp(TOPO_PROP_GROUP_DSTAB, nvpair_name(pg_nvp)) == 0 && nvpair_type(pg_nvp) == DATA_TYPE_STRING) { (void) nvpair_value_string(pg_nvp, &dstab); - } else if (strcmp(TOPO_PROP_GROUP_VERSION, + continue; + } + + if (strcmp(TOPO_PROP_GROUP_VERSION, nvpair_name(pg_nvp)) == 0 && nvpair_type(pg_nvp) == DATA_TYPE_INT32) { (void) nvpair_value_int32(pg_nvp, &version); + continue; + } + + if ((match || all) && !pg_done) { + print_pgroup(thp, node, pgn, dstab, nstab, + version); + pg_done++; + } + + /* + * Print property group and property name-value pair + */ + if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) + == 0 && nvpair_type(pg_nvp) == DATA_TYPE_NVLIST) { + (void) nvpair_value_nvlist(pg_nvp, &pv_nv); + if ((match || all) && pg_done) { + print_prop_nameval(thp, pv_nv); + } + } - if (!pg_done) { - if (pgn && dstab && nstab && version) { - print_pgroup(pgn, dstab, nstab, - version, skip); - pg_done++; + } + if (match && !all) + return; + } +} + +static void +set_prop(topo_hdl_t *thp, tnode_t *node, nvlist_t *fmri, struct prop_args *pp) +{ + int ret, err = 0; + topo_type_t type; + nvlist_t *nvl, *f = NULL; + char *end; + + if (pp->prop == NULL || pp->type == NULL || pp->value == NULL) + return; + + if ((type = str2type(pp->type)) == TOPO_TYPE_INVALID) { + (void) fprintf(stderr, "%s: invalid property type %s for %s\n", + g_pname, pp->type, pp->prop); + return; + } + + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { + (void) fprintf(stderr, "%s: nvlist allocation failed for " + "%s=%s:%s\n", g_pname, pp->prop, pp->type, pp->value); + return; + } + ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pp->prop); + ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type); + if (ret != 0) { + (void) fprintf(stderr, "%s: invalid property type %s for %s\n", + g_pname, pp->type, pp->prop); + nvlist_free(nvl); + return; + } + + errno = 0; + switch (type) { + case TOPO_TYPE_INT32: + { + int32_t val; + + val = strtol(pp->value, &end, 0); + if (errno == ERANGE) { + ret = -1; + break; + } + ret = nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, val); + break; + } + case TOPO_TYPE_UINT32: + { + uint32_t val; + + val = strtoul(pp->value, &end, 0); + if (errno == ERANGE) { + ret = -1; + break; + } + ret = nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, val); + break; + } + case TOPO_TYPE_INT64: + { + int64_t val; + + val = strtoll(pp->value, &end, 0); + if (errno == ERANGE) { + ret = -1; + break; + } + ret = nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, val); + break; + } + case TOPO_TYPE_UINT64: + { + uint64_t val; + + val = strtoull(pp->value, &end, 0); + if (errno == ERANGE) { + ret = -1; + break; + } + ret = nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, val); + break; + } + case TOPO_TYPE_STRING: + { + ret = nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, + pp->value); + break; + } + case TOPO_TYPE_FMRI: + { + if ((ret = topo_fmri_str2nvl(thp, pp->value, &f, &err)) + < 0) + break; + + if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, + f)) != 0) + err = ETOPO_PROP_NVL; + break; + } + default: + ret = -1; + } + + if (ret != 0) { + (void) fprintf(stderr, "%s: unable to set property value for " + "%s: %s\n", g_pname, pp->prop, topo_strerror(err)); + nvlist_free(nvl); + return; + } + + if (node != NULL) { + if (topo_prop_setprop(node, pp->group, nvl, TOPO_PROP_MUTABLE, + f, &ret) < 0) { + (void) fprintf(stderr, "%s: unable to set property " + "value for " "%s=%s:%s: %s\n", g_pname, pp->prop, + pp->type, pp->value, topo_strerror(ret)); + nvlist_free(nvl); + nvlist_free(f); + return; + } + } else { + if (topo_fmri_setprop(thp, fmri, pp->group, nvl, + TOPO_PROP_MUTABLE, f, &ret) < 0) { + (void) fprintf(stderr, "%s: unable to set property " + "value for " "%s=%s:%s: %s\n", g_pname, pp->prop, + pp->type, pp->value, topo_strerror(ret)); + nvlist_free(nvl); + nvlist_free(f); + return; + } + } + + nvlist_free(nvl); + + /* + * Now, get the property back for printing + */ + if (node != NULL) { + if (topo_prop_getprop(node, pp->group, pp->prop, f, &nvl, + &err) < 0) { + (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n", + g_pname, pp->group, pp->prop, topo_strerror(err)); + nvlist_free(f); + return; + } + } else { + if (topo_fmri_getprop(thp, fmri, pp->group, pp->prop, + f, &nvl, &err) < 0) { + (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n", + g_pname, pp->group, pp->prop, topo_strerror(err)); + nvlist_free(f); + return; + } + } + + print_pgroup(thp, node, pp->group, NULL, NULL, 0); + print_prop_nameval(thp, nvl); + nvlist_free(nvl); + + nvlist_free(f); +} + +static void +print_props(topo_hdl_t *thp, tnode_t *node) +{ + int i, err; + nvlist_t *nvl; + struct prop_args *pp; + + if (pcnt == 0) + return; + + for (i = 0; i < pcnt; ++i) { + pp = pargs[i]; + + if (pp->group == NULL) + continue; + + /* + * If we have a valid value, this is a request to + * set a property. Otherwise, just print the property + * group and any specified properties. + */ + if (pp->value == NULL) { + if (pp->prop == NULL) { + + /* + * Print all properties in this group + */ + if ((nvl = topo_prop_getprops(node, &err)) + == NULL) { + (void) fprintf(stderr, "%s: failed to " + "get %s: %s\n", g_pname, + pp->group, + topo_strerror(err)); + continue; } else { + print_all_props(thp, node, nvl, + pp->group); + nvlist_free(nvl); continue; } - /* - * Print property name-value pair - */ - } else if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) - == 0 && nvpair_type(pg_nvp) == DATA_TYPE_NVLIST) { - (void) nvpair_value_nvlist(pg_nvp, &pv_nv); - print_prop_nameval(thp, pv_nv, skip); - } + if (topo_prop_getprop(node, pp->group, pp->prop, + NULL, &nvl, &err) < 0) { + (void) fprintf(stderr, "%s: failed to get " + "%s.%s: %s\n", g_pname, + pp->group, pp->prop, + topo_strerror(err)); + continue; + } else { + print_pgroup(thp, node, pp->group, NULL, + NULL, 0); + print_prop_nameval(thp, nvl); + nvlist_free(nvl); + } + } else { + set_prop(thp, node, NULL, pp); } - pg_done = 0; - skip = 0; } } /*ARGSUSED*/ static int -print_tnode(topo_hdl_t *thp, tnode_t *node, void *arg) +walk_node(topo_hdl_t *thp, tnode_t *node, void *arg) { int err; nvlist_t *nvl; + nvlist_t *rsrc; + char *s; if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) { print_everstyle(node); return (TOPO_WALK_NEXT); } - print_fmri(thp, node); + if (topo_node_resource(node, &rsrc, &err) < 0) { + (void) fprintf(stderr, "%s: failed to get resource: " + "%s", g_pname, topo_strerror(err)); + return (TOPO_WALK_NEXT); + } + if (topo_fmri_nvl2str(thp, rsrc, &s, &err) < 0) { + (void) fprintf(stderr, "%s: failed to convert " + "resource to FMRI string: %s", g_pname, + topo_strerror(err)); + nvlist_free(rsrc); + return (TOPO_WALK_NEXT); + } - if (opt_V || opt_P) { + if (g_fmri != NULL && fnmatch(g_fmri, s, 0) != 0) { + nvlist_free(rsrc); + topo_hdl_strfree(thp, s); + return (TOPO_WALK_NEXT); + } + + print_node(thp, node, rsrc, s); + topo_hdl_strfree(thp, s); + nvlist_free(rsrc); + + if (opt_V || opt_all) { if ((nvl = topo_prop_getprops(node, &err)) == NULL) { (void) fprintf(stderr, "%s: failed to get " "properties for %s=%d: %s\n", g_pname, topo_node_name(node), topo_node_instance(node), topo_strerror(err)); } else { - print_props(thp, nvl, opt_P); + print_all_props(thp, node, nvl, ALL); nvlist_free(nvl); } + } else if (pcnt > 0) { + print_props(thp, node); } printf("\n"); @@ -501,100 +759,93 @@ return (TOPO_WALK_NEXT); } -int -main(int argc, char *argv[]) +static void +get_pargs(int argc, char *argv[]) { - topo_hdl_t *thp; - topo_walk_t *twp; - char *uuid; - int c, err = 0; - - g_pname = argv[0]; + struct prop_args *pp; + char c, *s, *p; + int i = 0; - while (optind < argc) { - while ((c = getopt(argc, argv, "aCdeP:pR:s:vVx")) != -1) { - switch (c) { - case 'C': - atexit(abort); - break; - case 'd': - opt_d++; - break; - case 'e': - opt_e++; - break; - case 'P': - opt_P = optarg; + if ((pargs = malloc(sizeof (struct prop_args *) * pcnt)) == NULL) { + (void) fprintf(stderr, "%s: failed to allocate property " + "arguments\n", g_pname); + return; + } + + for (optind = 1; (c = getopt(argc, argv, optstr)) != EOF; ) { + if (c == 'P') { + + if (strcmp(optarg, ALL) == 0) { + opt_all++; break; - case 'p': - opt_p++; - break; - case 'V': - opt_V++; - break; - case 'R': - opt_R = optarg; - break; - case 's': - opt_s = optarg; + } + + if ((pp = pargs[i] = malloc(sizeof (struct prop_args))) + == NULL) { + (void) fprintf(stderr, "%s: failed to " + "allocate propertyarguments\n", g_pname); + return; + } + ++i; + pp->group = NULL; + pp->prop = NULL; + pp->type = NULL; + pp->value = NULL; + + p = optarg; + if ((s = strchr(p, '.')) != NULL) { + *s++ = '\0'; /* strike out delimiter */ + pp->group = p; + p = s; + if ((s = strchr(p, '=')) != NULL) { + *s++ = '\0'; /* strike out delimiter */ + pp->prop = p; + p = s; + if ((s = strchr(p, ':')) != NULL) { + *s++ = '\0'; + pp->type = p; + pp->value = s; + } else { + (void) fprintf(stderr, "%s: " + "property type not " + "specified for assignment " + " of %s.%s\n", g_pname, + pp->group, pp->prop); + break; + } + } else { + pp->prop = p; + } + } else { + pp->group = p; + } + if (i >= pcnt) break; - case 'x': - opt_x++; - break; - default: - return (usage(stderr)); - } - } - - if (optind < argc) { - (void) fprintf(stderr, "%s: illegal argument -- %s\n", - g_pname, argv[optind]); - return (FMTOPO_EXIT_USAGE); } } - if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) { - (void) fprintf(stderr, "%s: failed to open topology tree: %s\n", - g_pname, topo_strerror(err)); - return (FMTOPO_EXIT_ERROR); - } - - if (opt_d) - topo_debug_set(thp, "module", "stderr"); + if (opt_all > 0) { + int j; - if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) { - (void) fprintf(stderr, "%s: failed to snapshot topology: %s\n", - g_pname, topo_strerror(err)); - topo_close(thp); - return (FMTOPO_EXIT_ERROR); - } else if (err != 0) { - (void) fprintf(stderr, "%s: topology snapshot incomplete\n", - g_pname); + for (j = 0; j < i; ++j) + free(pargs[i]); + free(pargs); + pargs = NULL; } - +} - if (opt_x) { - err = 0; - if (topo_xml_print(thp, stdout, opt_s, &err) < 0) - (void) fprintf(stderr, "%s: failed to print xml " - "formatted topology:%s", g_pname, - topo_strerror(err)); +static int +walk_topo(topo_hdl_t *thp, char *uuid) +{ + int err; + topo_walk_t *twp; - topo_hdl_strfree(thp, uuid); - topo_snap_release(thp); - topo_close(thp); - return (err ? FMTOPO_EXIT_ERROR : FMTOPO_EXIT_SUCCESS); - } - if ((twp = topo_walk_init(thp, opt_s, print_tnode, NULL, &err)) + if ((twp = topo_walk_init(thp, opt_s, walk_node, NULL, &err)) == NULL) { (void) fprintf(stderr, "%s: failed to walk %s topology:" " %s\n", g_pname, opt_s, topo_strerror(err)); - topo_hdl_strfree(thp, uuid); - topo_snap_release(thp); - topo_close(thp); - - return (err ? FMTOPO_EXIT_ERROR : FMTOPO_EXIT_SUCCESS); + return (-1); } /* @@ -610,20 +861,311 @@ (void) printf("\n"); } - topo_hdl_strfree(thp, uuid); - if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) { (void) fprintf(stderr, "%s: failed to walk topology\n", g_pname); topo_walk_fini(twp); - topo_snap_release(thp); - topo_close(thp); - return (FMTOPO_EXIT_ERROR); + return (-1); } topo_walk_fini(twp); - topo_snap_release(thp); - topo_close(thp); + + return (0); +} + +static void +print_fmri_pgroup(topo_hdl_t *thp, const char *pgn, nvlist_t *nvl) +{ + char *dstab = NULL, *nstab = NULL; + int32_t version = -1; + nvlist_t *pnvl; + nvpair_t *pnvp; + + (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_NSTAB, &nstab); + (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_DSTAB, &dstab); + (void) nvlist_lookup_int32(nvl, TOPO_PROP_GROUP_VERSION, &version); + + print_pgroup(thp, NULL, pgn, dstab, nstab, version); + + for (pnvp = nvlist_next_nvpair(nvl, NULL); pnvp != NULL; + pnvp = nvlist_next_nvpair(nvl, pnvp)) { + + /* + * Print property group and property name-value pair + */ + if (strcmp(TOPO_PROP_VAL, nvpair_name(pnvp)) + == 0 && nvpair_type(pnvp) == DATA_TYPE_NVLIST) { + (void) nvpair_value_nvlist(pnvp, &pnvl); + print_prop_nameval(thp, pnvl); + + } + + } +} + +static void +print_fmri_props(topo_hdl_t *thp, nvlist_t *nvl) +{ + int i, err; + struct prop_args *pp; + nvlist_t *pnvl; + + for (i = 0; i < pcnt; ++i) { + pp = pargs[i]; + + if (pp->group == NULL) + continue; + + pnvl = NULL; + + /* + * If we have a valid value, this is a request to + * set a property. Otherwise, just print the property + * group and any specified properties. + */ + if (pp->value == NULL) { + if (pp->prop == NULL) { + + /* + * Print all properties in this group + */ + if (topo_fmri_getpgrp(thp, nvl, pp->group, + &pnvl, &err) < 0) { + (void) fprintf(stderr, "%s: failed to " + "get group %s: %s\n", g_pname, + pp->group, topo_strerror(err)); + continue; + } else { + print_fmri_pgroup(thp, pp->group, pnvl); + nvlist_free(pnvl); + continue; + } + } + if (topo_fmri_getprop(thp, nvl, pp->group, pp->prop, + NULL, &pnvl, &err) < 0) { + (void) fprintf(stderr, "%s: failed to get " + "%s.%s: %s\n", g_pname, + pp->group, pp->prop, + topo_strerror(err)); + continue; + } else { + print_fmri_pgroup(thp, pp->group, pnvl); + print_prop_nameval(thp, pnvl); + nvlist_free(nvl); + } + } else { + set_prop(thp, NULL, nvl, pp); + } + } +} + +void +print_fmri(topo_hdl_t *thp, char *uuid) +{ + int ret, err; + nvlist_t *nvl; + char buf[32]; + time_t tod = time(NULL); + + if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) { + (void) fprintf(stderr, "%s: failed to convert %s to nvlist: " + "%s\n", g_pname, g_fmri, topo_strerror(err)); + return; + } + + printf("TIME UUID\n"); + (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod)); + (void) printf("%-15s %-32s\n", buf, uuid); + (void) printf("\n"); + + (void) printf("%s\n", (char *)g_fmri); + + if (opt_p && !(pcnt > 0 || opt_V || opt_all)) { + char *aname = NULL, *fname = NULL, *lname = NULL; + nvlist_t *asru = NULL; + nvlist_t *fru = NULL; + + if (topo_fmri_asru(thp, nvl, &asru, &err) == 0) + (void) topo_fmri_nvl2str(thp, asru, &aname, &err); + if (topo_fmri_fru(thp, nvl, &fru, &err) == 0) + (void) topo_fmri_nvl2str(thp, fru, &fname, &err); + (void) topo_fmri_label(thp, nvl, &lname, &err); + + nvlist_free(fru); + nvlist_free(asru); + + if (aname != NULL) { + (void) printf("\tASRU: %s\n", aname); + topo_hdl_strfree(thp, aname); + } else { + (void) printf("\tASRU: -\n"); + } + if (fname != NULL) { + (void) printf("\tFRU: %s\n", fname); + topo_hdl_strfree(thp, fname); + } else { + (void) printf("\tFRU: -\n"); + } + if (lname != NULL) { + (void) printf("\tLabel: %s\n", lname); + topo_hdl_strfree(thp, lname); + } else { + (void) printf("\tLabel: -\n"); + } + } + + if (opt_S) { + if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) { + (void) printf("\tPresent: -\n"); + (void) printf("\tUnusable: -\n"); + return; + } + + if ((ret = topo_fmri_present(thp, nvl, &err)) < 0) + (void) printf("\tPresent: -\n"); + else + (void) printf("\tPresent: %s\n", + ret ? "true" : "false"); + + if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0) + (void) printf("\tUnusable: -\n"); + else + (void) printf("\tUnusable: %s\n", + ret ? "true" : "false"); + + nvlist_free(nvl); + } + + if (pcnt > 0) + print_fmri_props(thp, nvl); +} + +int +fmtopo_exit(topo_hdl_t *thp, char *uuid, int err) +{ + if (uuid != NULL) + topo_hdl_strfree(thp, uuid); + + if (thp != NULL) { + topo_snap_release(thp); + topo_close(thp); + } + + if (pargs) { + int i; + for (i = 0; i < pcnt; ++i) + free(pargs[i]); + free(pargs); + } + + return (err); +} + +int +main(int argc, char *argv[]) +{ + topo_hdl_t *thp = NULL; + char *uuid = NULL; + int c, err = 0; + + g_pname = argv[0]; + + while (optind < argc) { + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'C': + atexit(abort); + break; + case 'd': + opt_d++; + break; + case 'e': + opt_e++; + break; + case 'P': + pcnt++; + break; + case 'p': + opt_p++; + break; + case 'V': + opt_V++; + break; + case 'R': + opt_R = optarg; + break; + case 's': + opt_s = optarg; + break; + case 'S': + opt_S++; + break; + case 't': + opt_t++; + break; + case 'x': + opt_x++; + break; + default: + return (usage(stderr)); + } + } + + if (optind < argc) { + if (g_fmri != NULL) { + (void) fprintf(stderr, "%s: illegal argument " + "-- %s\n", g_pname, argv[optind]); + return (FMTOPO_EXIT_USAGE); + } else { + g_fmri = argv[optind++]; + } + } + } + + if (pcnt > 0) + get_pargs(argc, argv); + + if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) { + (void) fprintf(stderr, "%s: failed to open topology tree: %s\n", + g_pname, topo_strerror(err)); + return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); + } + + if (opt_d) + topo_debug_set(thp, "module", "stderr"); + + if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) { + (void) fprintf(stderr, "%s: failed to snapshot topology: %s\n", + g_pname, topo_strerror(err)); + return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); + } else if (err != 0) { + (void) fprintf(stderr, "%s: topology snapshot incomplete\n", + g_pname); + } + + + if (opt_x) { + err = 0; + if (topo_xml_print(thp, stdout, opt_s, &err) < 0) + (void) fprintf(stderr, "%s: failed to print xml " + "formatted topology:%s", g_pname, + topo_strerror(err)); + + return (fmtopo_exit(thp, uuid, err ? FMTOPO_EXIT_ERROR : + FMTOPO_EXIT_SUCCESS)); + } + + if (opt_t || walk_topo(thp, uuid) < 0) { + if (g_fmri != NULL) + /* + * Try getting some useful information + */ + print_fmri(thp, uuid); + + return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); + } + + topo_hdl_strfree(thp, uuid); return (FMTOPO_EXIT_SUCCESS); }
--- a/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c Mon Apr 23 15:34:38 2007 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -332,6 +332,19 @@ return (WALK_NEXT); } +static void +dump_propmethod(uintptr_t addr) +{ + topo_propmethod_t pm; + + if (mdb_vread(&pm, sizeof (pm), addr) != sizeof (pm)) { + mdb_warn("failed to read topo_propmethod at %p", addr); + return; + } + + mdb_printf(" method: %-32s version: %-16s args: %p\n", + pm.tpm_name, pm.tpm_version, pm.tpm_args); +} /* * Dump the given property value. For the actual property values @@ -373,6 +386,10 @@ default: type = "unknown type"; } mdb_printf(" %-32s %-16s value: %p\n", name, type, pval.tp_val); + + if (pval.tp_method != NULL) + dump_propmethod((uintptr_t)pval.tp_method); + return (WALK_NEXT); }
--- a/usr/src/lib/fm/topo/libtopo/Makefile.com Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/Makefile.com Mon Apr 23 15:34:38 2007 -0700 @@ -105,6 +105,8 @@ sh ../common/mkerror.sh liberrors < ../common/topo_error.h > $@ sh ../common/mkerror.sh properrors < ../common/libtopo.h >> $@ sh ../common/mkerror.sh methoderrors < ../common/libtopo.h >> $@ + sh ../common/mkerror.sh fmrierrors < ../common/libtopo.h >> $@ + sh ../common/mkerror.sh hdlerrors < ../common/libtopo.h >> $@ sh ../common/mkerror.sh moderrors < ../common/topo_mod.h >> $@ include ../../../../Makefile.targ
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/hc.c Mon Apr 23 15:34:38 2007 -0700 @@ -21,7 +21,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -45,6 +45,7 @@ #include <topo_method.h> #include <topo_subr.h> +#include <topo_prop.h> #include <hc.h> static int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, @@ -56,8 +57,18 @@ nvlist_t *, nvlist_t **); static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); +static int hc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int hc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); +static int hc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); +static int hc_fmri_prop_set(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); +static int hc_fmri_pgrp_get(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); static nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *, topo_instance_t inst, const nvlist_t *, const char *, const char *, @@ -70,8 +81,22 @@ TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl }, { TOPO_METH_COMPARE, TOPO_METH_COMPARE_DESC, TOPO_METH_COMPARE_VERSION, TOPO_STABILITY_INTERNAL, hc_compare }, + { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, + TOPO_STABILITY_INTERNAL, hc_fmri_present }, + { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, + TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, + hc_fmri_unusable }, { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, TOPO_STABILITY_INTERNAL, hc_fmri_create_meth }, + { TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC, + TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL, + hc_fmri_prop_get }, + { TOPO_METH_PROP_SET, TOPO_METH_PROP_SET_DESC, + TOPO_METH_PROP_SET_VERSION, TOPO_STABILITY_INTERNAL, + hc_fmri_prop_set }, + { TOPO_METH_PGRP_GET, TOPO_METH_PGRP_GET_DESC, + TOPO_METH_PGRP_GET_VERSION, TOPO_STABILITY_INTERNAL, + hc_fmri_pgrp_get }, { NULL } }; @@ -272,24 +297,14 @@ topo_method_unregister_all(mp, node); } -/*ARGSUSED*/ static int -hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version, - nvlist_t *in, nvlist_t **out) +fmri_compare(topo_mod_t *mod, nvlist_t *nv1, nvlist_t *nv2) { uint8_t v1, v2; - nvlist_t *nv1, *nv2; nvlist_t **hcp1, **hcp2; int err, i; uint_t nhcp1, nhcp2; - if (version > TOPO_METH_COMPARE_VERSION) - return (topo_mod_seterrno(mod, EMOD_VER_NEW)); - - if (nvlist_lookup_nvlist(in, "nv1", &nv1) != 0 || - nvlist_lookup_nvlist(in, "nv2", &nv2) != 0) - return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); - if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 || nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 || v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION) @@ -325,6 +340,38 @@ return (1); } +/*ARGSUSED*/ +static int +hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int ret; + uint32_t compare; + nvlist_t *nv1, *nv2; + + if (version > TOPO_METH_COMPARE_VERSION) + return (topo_mod_seterrno(mod, EMOD_VER_NEW)); + + if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV1, &nv1) != 0 || + nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV1, &nv2) != 0) + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + + ret = fmri_compare(mod, nv1, nv2); + if (ret < 0) + return (-1); + + compare = ret; + if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) == 0) { + if (nvlist_add_uint32(*out, TOPO_METH_COMPARE_RET, + compare) == 0) + return (0); + else + nvlist_free(*out); + } + + return (-1); +} + static ssize_t fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) { @@ -518,12 +565,12 @@ char *hc, *fromstr; char *starti, *startn, *endi, *endi2; char *ne, *ns; - char *cname; + char *cname = NULL; char *find; - char *cid; + char *cid = NULL; int nslashes = 0; int npairs = 0; - int i, e; + int i; if ((hc = topo_mod_strdup(mod, fmri + 5)) == NULL) return (NULL); @@ -561,7 +608,11 @@ find = fromstr; - pa = topo_mod_alloc(mod, npairs * sizeof (nvlist_t *)); + if ((pa = topo_mod_alloc(mod, npairs * sizeof (nvlist_t *))) == NULL) { + topo_mod_strfree(mod, hc); + return (NULL); + } + /* * We go through a pretty complicated procedure to find the * name and id for each pair. That's because, unfortunately, @@ -581,7 +632,8 @@ if (starti == NULL) break; *starti = '\0'; - cname = topo_mod_strdup(mod, startn); + if ((cname = topo_mod_strdup(mod, startn)) == NULL) + break; *starti++ = '='; endi = strchr(starti, '='); if (endi != NULL) { @@ -591,33 +643,34 @@ break; *endi = '='; *endi2 = '\0'; - cid = topo_mod_strdup(mod, starti); + if ((cid = topo_mod_strdup(mod, starti)) == NULL) + break; *endi2 = '/'; find = endi2; } else { - cid = topo_mod_strdup(mod, starti); + if ((cid = topo_mod_strdup(mod, starti)) == NULL) + break; find = starti + strlen(starti); } - if ((e = topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME)) != 0) { - topo_mod_strfree(mod, cname); - topo_mod_strfree(mod, cid); + if (topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME) < 0) break; - } - e = nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname); - e |= nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid); + if (nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname) || + nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid)) + break; topo_mod_strfree(mod, cname); topo_mod_strfree(mod, cid); + cname = NULL; + cid = NULL; + } - if (e != 0) { - break; - } - } + topo_mod_strfree(mod, cname); + topo_mod_strfree(mod, cid); + if (i < npairs) { while (i >= 0) - if (pa[i--] != NULL) - nvlist_free(pa[i + 1]); + nvlist_free(pa[i + 1]); topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); topo_mod_strfree(mod, hc); return (NULL); @@ -966,3 +1019,465 @@ return (-1); return (0); } + +struct hc_walk { + topo_mod_walk_cb_t hcw_cb; + void *hcw_priv; + topo_walk_t *hcw_wp; + nvlist_t **hcw_list; + uint_t hcw_index; + uint_t hcw_end; +}; + +/* + * Generic walker for the hc-scheme topo tree. This function uses the + * hierachical nature of the hc-scheme to step through efficiently through + * the topo hc tree. Node lookups are done by topo_walk_byid() at each + * component level to avoid unnecessary traversal of the tree. + * + */ +static int +hc_walker(topo_mod_t *mod, tnode_t *node, void *pdata) +{ + int i, err; + struct hc_walk *hwp = (struct hc_walk *)pdata; + char *name, *id; + topo_instance_t inst; + + i = hwp->hcw_index; + if (i > hwp->hcw_end) { + (void) topo_mod_seterrno(mod, ETOPO_PROP_NOENT); + return (TOPO_WALK_TERMINATE); + } + + err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name); + err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id); + + if (err != 0) { + (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); + return (TOPO_WALK_ERR); + } + + inst = atoi(id); + topo_mod_dprintf(mod, "hc_walker: walking node:%s=%d for hc:" + "%s=%d at %d, end at %d \n", topo_node_name(node), + topo_node_instance(node), name, inst, i, hwp->hcw_end); + if (i == hwp->hcw_end) { + /* + * We are at the end of the hc-list. Verify that + * the last node contains the name/instance we are looking for. + */ + if (strcmp(topo_node_name(node), name) == 0 && + inst == topo_node_instance(node)) { + if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv)) + != 0) { + (void) topo_mod_seterrno(mod, err); + topo_mod_dprintf(mod, "hc_walker: callback " + "failed: %s\n ", topo_mod_errmsg(mod)); + return (TOPO_WALK_ERR); + } + topo_mod_dprintf(mod, "hc_walker: callback " + "complete: terminate walk\n"); + return (TOPO_WALK_TERMINATE); + } else { + topo_mod_dprintf(mod, "hc_walker: %s=%d\n " + "not found\n", name, inst); + return (TOPO_WALK_TERMINATE); + } + } + + hwp->hcw_index = ++i; + err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name); + err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id); + if (err != 0) { + (void) topo_mod_seterrno(mod, err); + return (TOPO_WALK_ERR); + } + inst = atoi(id); + + topo_mod_dprintf(mod, "hc_walker: walk byid of %s=%d \n", name, + inst); + return (topo_walk_byid(hwp->hcw_wp, name, inst)); + +} + +static struct hc_walk * +hc_walk_init(topo_mod_t *mod, tnode_t *node, nvlist_t *rsrc, + topo_mod_walk_cb_t cb, void *pdata) +{ + int err; + uint_t sz; + struct hc_walk *hwp; + topo_walk_t *wp; + + if ((hwp = topo_mod_alloc(mod, sizeof (struct hc_walk))) == NULL) + (void) topo_mod_seterrno(mod, EMOD_NOMEM); + + if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hwp->hcw_list, + &sz) != 0) { + topo_mod_free(mod, hwp, sizeof (struct hc_walk)); + (void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL); + return (NULL); + } + + hwp->hcw_end = sz - 1; + hwp->hcw_index = 0; + hwp->hcw_priv = pdata; + hwp->hcw_cb = cb; + if ((wp = topo_mod_walk_init(mod, node, hc_walker, (void *)hwp, &err)) + == NULL) { + topo_mod_free(mod, hwp, sizeof (struct hc_walk)); + (void) topo_mod_seterrno(mod, err); + return (NULL); + } + + hwp->hcw_wp = wp; + + return (hwp); +} + +struct prop_lookup { + const char *pl_pgroup; + const char *pl_pname; + int pl_flag; + nvlist_t *pl_args; + nvlist_t *pl_rsrc; + nvlist_t *pl_prop; +}; + +/*ARGSUSED*/ +static int +hc_prop_get(topo_mod_t *mod, tnode_t *node, void *pdata) +{ + int err = 0; + + struct prop_lookup *plp = (struct prop_lookup *)pdata; + + (void) topo_prop_getprop(node, plp->pl_pgroup, plp->pl_pname, + plp->pl_args, &plp->pl_prop, &err); + + return (err); +} + +static int +hc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int err; + struct hc_walk *hwp; + struct prop_lookup *plp; + + if (version > TOPO_METH_PROP_GET_VERSION) + return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); + + if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + + err = nvlist_lookup_string(in, TOPO_PROP_GROUP, + (char **)&plp->pl_pgroup); + err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME, + (char **)&plp->pl_pname); + err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc); + if (err != 0) { + topo_mod_free(mod, plp, sizeof (struct prop_lookup)); + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + } + + /* + * Private args to prop method are optional + */ + if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args)) + != 0) { + if (err != ENOENT) { + topo_mod_free(mod, plp, sizeof (struct prop_lookup)); + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + } else { + plp->pl_args = NULL; + } + } + + plp->pl_prop = NULL; + if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_get, + (void *)plp)) != NULL) { + if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == + TOPO_WALK_ERR) + err = -1; + else + err = 0; + topo_walk_fini(hwp->hcw_wp); + } else { + err = -1; + } + + topo_mod_free(mod, hwp, sizeof (struct hc_walk)); + + if (plp->pl_prop != NULL) + *out = plp->pl_prop; + + topo_mod_free(mod, plp, sizeof (struct prop_lookup)); + + return (err); +} + +/*ARGSUSED*/ +static int +hc_pgrp_get(topo_mod_t *mod, tnode_t *node, void *pdata) +{ + int err = 0; + + struct prop_lookup *plp = (struct prop_lookup *)pdata; + + (void) topo_prop_getpgrp(node, plp->pl_pgroup, &plp->pl_prop, &err); + + return (err); +} + +static int +hc_fmri_pgrp_get(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int err; + struct hc_walk *hwp; + struct prop_lookup *plp; + + if (version > TOPO_METH_PGRP_GET_VERSION) + return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); + + if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + + err = nvlist_lookup_string(in, TOPO_PROP_GROUP, + (char **)&plp->pl_pgroup); + err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc); + if (err != 0) { + topo_mod_free(mod, plp, sizeof (struct prop_lookup)); + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + } + + plp->pl_prop = NULL; + if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_pgrp_get, + (void *)plp)) != NULL) { + if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == + TOPO_WALK_ERR) + err = -1; + else + err = 0; + topo_walk_fini(hwp->hcw_wp); + } else { + err = -1; + } + + topo_mod_free(mod, hwp, sizeof (struct hc_walk)); + + if (plp->pl_prop != NULL) + *out = plp->pl_prop; + + topo_mod_free(mod, plp, sizeof (struct prop_lookup)); + + return (err); +} + +/*ARGSUSED*/ +static int +hc_prop_setprop(topo_mod_t *mod, tnode_t *node, void *pdata) +{ + int err = 0; + + struct prop_lookup *plp = (struct prop_lookup *)pdata; + + (void) topo_prop_setprop(node, plp->pl_pgroup, plp->pl_prop, + plp->pl_flag, plp->pl_args, &err); + + return (err); +} + +/*ARGSUSED*/ +static int +hc_fmri_prop_set(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int err; + struct hc_walk *hwp; + struct prop_lookup *plp; + + if (version > TOPO_METH_PROP_SET_VERSION) + return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); + + if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + + err = nvlist_lookup_string(in, TOPO_PROP_GROUP, + (char **)&plp->pl_pgroup); + err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc); + err |= nvlist_lookup_nvlist(in, TOPO_PROP_VAL, &plp->pl_prop); + err |= nvlist_lookup_int32(in, TOPO_PROP_FLAG, &plp->pl_flag); + if (err != 0) { + topo_mod_free(mod, plp, sizeof (struct prop_lookup)); + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + } + + /* + * Private args to prop method are optional + */ + if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args)) + != 0) { + if (err != ENOENT) + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + else + plp->pl_args = NULL; + } + + if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_setprop, + (void *)plp)) != NULL) { + if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == + TOPO_WALK_ERR) + err = -1; + else + err = 0; + topo_walk_fini(hwp->hcw_wp); + } else { + err = -1; + } + + topo_mod_free(mod, hwp, sizeof (struct hc_walk)); + topo_mod_free(mod, plp, sizeof (struct prop_lookup)); + + return (err); +} + +struct hc_args { + nvlist_t *ha_fmri; + nvlist_t *ha_nvl; +}; + +static int +hc_is_present(topo_mod_t *mod, tnode_t *node, void *pdata) +{ + int err; + struct hc_args *hap = (struct hc_args *)pdata; + + /* + * check with the enumerator that created this FMRI + * (topo node) + */ + if (topo_method_invoke(node, TOPO_METH_PRESENT, + TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl, + &err) < 0) { + + /* + * Err on the side of caution and return present + */ + if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0) + if (nvlist_add_uint32(hap->ha_nvl, + TOPO_METH_PRESENT_RET, 1) == 0) + return (0); + + return (ETOPO_PROP_NVL); + } + + return (err); +} + +static int +hc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int err; + struct hc_walk *hwp; + struct hc_args *hap; + + if (version > TOPO_METH_PRESENT_VERSION) + return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); + + if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + + hap->ha_fmri = in; + hap->ha_nvl = NULL; + if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_present, + (void *)hap)) != NULL) { + if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == + TOPO_WALK_ERR) + err = -1; + else + err = 0; + topo_walk_fini(hwp->hcw_wp); + } else { + err = -1; + } + + topo_mod_free(mod, hwp, sizeof (struct hc_walk)); + + if (hap->ha_nvl != NULL) + *out = hap->ha_nvl; + + topo_mod_free(mod, hap, sizeof (struct hc_args)); + + return (err); +} + +static int +hc_unusable(topo_mod_t *mod, tnode_t *node, void *pdata) +{ + int err; + struct hc_args *hap = (struct hc_args *)pdata; + + /* + * check with the enumerator that created this FMRI + * (topo node) + */ + if (topo_method_invoke(node, TOPO_METH_UNUSABLE, + TOPO_METH_UNUSABLE_VERSION, hap->ha_fmri, &hap->ha_nvl, + &err) < 0) { + + /* + * Err on the side of caution and return usable + */ + if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0) + if (nvlist_add_uint32(hap->ha_nvl, + TOPO_METH_UNUSABLE_RET, 0) == 0) + return (0); + + return (ETOPO_PROP_NVL); + } + + return (err); +} + +static int +hc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int err; + struct hc_walk *hwp; + struct hc_args *hap; + + if (version > TOPO_METH_UNUSABLE_VERSION) + return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); + + if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + + hap->ha_fmri = in; + hap->ha_nvl = NULL; + if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_unusable, + (void *)hap)) != NULL) { + if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == + TOPO_WALK_ERR) + err = -1; + else + err = 0; + topo_walk_fini(hwp->hcw_wp); + } else { + err = -1; + } + + topo_mod_free(mod, hwp, sizeof (struct hc_walk)); + + if (hap->ha_nvl != NULL) + *out = hap->ha_nvl; + + topo_mod_free(mod, hap, sizeof (struct hc_args)); + + return (err); +}
--- a/usr/src/lib/fm/topo/libtopo/common/libtopo.h Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h Mon Apr 23 15:34:38 2007 -0700 @@ -45,60 +45,13 @@ typedef uint32_t topo_version_t; /* - * Topo stability attributes - * - * Each topology node advertises the name and data stability of each of its - * modules and properties. (see attributes(5)) + * The following functions, error codes and data structures are private + * to libtopo snapshot consumers and enumerator modules. */ - -typedef enum topo_stability { - TOPO_STABILITY_UNKNOWN = 0, /* private to libtopo */ - TOPO_STABILITY_INTERNAL, /* private to libtopo */ - TOPO_STABILITY_PRIVATE, /* private to Sun */ - TOPO_STABILITY_OBSOLETE, /* scheduled for removal */ - TOPO_STABILITY_EXTERNAL, /* not controlled by Sun */ - TOPO_STABILITY_UNSTABLE, /* new or rapidly changing */ - TOPO_STABILITY_EVOLVING, /* less rapidly changing */ - TOPO_STABILITY_STABLE, /* mature interface from Sun */ - TOPO_STABILITY_STANDARD /* industry standard */ -} topo_stability_t; - -#define TOPO_STABILITY_MAX TOPO_STABILITY_STANDARD /* max valid stab */ - -typedef enum { - TOPO_TYPE_INVALID = 0, - TOPO_TYPE_BOOLEAN, /* boolean */ - TOPO_TYPE_INT32, /* int32_t */ - TOPO_TYPE_UINT32, /* uint32_t */ - TOPO_TYPE_INT64, /* int64_t */ - TOPO_TYPE_UINT64, /* uint64_t */ - TOPO_TYPE_STRING, /* const char* */ - TOPO_TYPE_TIME, /* uint64_t */ - TOPO_TYPE_SIZE, /* uint64_t */ - TOPO_TYPE_FMRI, /* nvlist_t */ - TOPO_TYPE_INT32_ARRAY, /* array of int32_t */ - TOPO_TYPE_UINT32_ARRAY, /* array of uint32_t */ - TOPO_TYPE_INT64_ARRAY, /* array of int64_t */ - TOPO_TYPE_UINT64_ARRAY, /* array of uint64_t */ - TOPO_TYPE_STRING_ARRAY, /* array of const char* */ - TOPO_TYPE_FMRI_ARRAY /* array of nvlist_t */ -} topo_type_t; - -typedef struct topo_pgroup_info { - const char *tpi_name; /* property group name */ - topo_stability_t tpi_namestab; /* stability of group name */ - topo_stability_t tpi_datastab; /* stability of all property values */ - topo_version_t tpi_version; /* version of pgroup definition */ -} topo_pgroup_info_t; - -extern topo_stability_t topo_name2stability(const char *); -extern const char *topo_stability2name(topo_stability_t); - extern topo_hdl_t *topo_open(int, const char *, int *); extern void topo_close(topo_hdl_t *); extern char *topo_snap_hold(topo_hdl_t *, const char *, int *); extern void topo_snap_release(topo_hdl_t *); -extern int topo_xml_print(topo_hdl_t *, FILE *, const char *scheme, int *); /* * Snapshot walker support @@ -110,10 +63,16 @@ extern int topo_walk_step(topo_walk_t *, int); extern void topo_walk_fini(topo_walk_t *); +/* + * Walk status returned from walker + */ #define TOPO_WALK_ERR -1 #define TOPO_WALK_NEXT 0 #define TOPO_WALK_TERMINATE 1 +/* + * Types of walks: depth-first (child) or breadth-first (sibling) + */ #define TOPO_WALK_CHILD 0x0001 #define TOPO_WALK_SIBLING 0x0002 @@ -131,8 +90,6 @@ int *); extern int topo_fmri_label(topo_hdl_t *, nvlist_t *, char **, int *); extern int topo_fmri_compare(topo_hdl_t *, nvlist_t *, nvlist_t *, int *); -extern int topo_fmri_invoke(topo_hdl_t *, nvlist_t *, topo_walk_cb_t, void *, - int *); /* * Topo node utilities: callable from topo_walk_step() callback or module @@ -148,9 +105,6 @@ extern int topo_method_invoke(tnode_t *node, const char *, topo_version_t, nvlist_t *, nvlist_t **, int *); -extern int topo_pgroup_create(tnode_t *, const topo_pgroup_info_t *, int *); -extern void topo_pgroup_destroy(tnode_t *, const char *); -extern topo_pgroup_info_t *topo_pgroup_info(tnode_t *, const char *, int *); extern int topo_prop_get_int32(tnode_t *, const char *, const char *, int32_t *, int *); extern int topo_prop_get_uint32(tnode_t *, const char *, const char *, @@ -175,32 +129,6 @@ char ***, uint_t *, int *); extern int topo_prop_get_fmri_array(tnode_t *, const char *, const char *, nvlist_t ***, uint_t *, int *); -extern int topo_prop_set_int32(tnode_t *, const char *, const char *, int, - int32_t, int *); -extern int topo_prop_set_uint32(tnode_t *, const char *, const char *, int, - uint32_t, int *); -extern int topo_prop_set_int64(tnode_t *, const char *, const char *, - int, int64_t, int *); -extern int topo_prop_set_uint64(tnode_t *, const char *, const char *, - int, uint64_t, int *); -extern int topo_prop_set_string(tnode_t *, const char *, const char *, - int, const char *, int *); -extern int topo_prop_set_fmri(tnode_t *, const char *, const char *, - int, const nvlist_t *, int *); -extern int topo_prop_set_int32_array(tnode_t *, const char *, const char *, int, - int32_t *, uint_t, int *); -extern int topo_prop_set_uint32_array(tnode_t *, const char *, const char *, - int, uint32_t *, uint_t, int *); -extern int topo_prop_set_int64_array(tnode_t *, const char *, const char *, - int, int64_t *, uint_t, int *); -extern int topo_prop_set_uint64_array(tnode_t *, const char *, const char *, - int, uint64_t *, uint_t, int *); -extern int topo_prop_set_string_array(tnode_t *, const char *, const char *, - int, const char **, uint_t, int *); -extern int topo_prop_set_fmri_array(tnode_t *, const char *, const char *, - int, const nvlist_t **, uint_t, int *); -extern nvlist_t *topo_prop_getprops(tnode_t *, int *err); -extern int topo_prop_inherit(tnode_t *, const char *, const char *, int *); #define TOPO_PROP_IMMUTABLE 0 #define TOPO_PROP_MUTABLE 1 @@ -221,6 +149,135 @@ #define TOPO_PROP_ISA "isa" #define TOPO_PROP_MACHINE "machine" +/* + * These enum definitions are used to define a set of error tags associated with + * libtopo error conditions occuring during the adminstration of + * properties, invocation of methods and fmri-based queries. The shell script + * mkerror.sh is used to parse this file and create a corresponding topo_error.c + * source file. + * + * If you do something other than add a new error tag here, you may need to + * update the mkerror shell script as it is based upon simple regexps. + */ +typedef enum topo_prop_errno { + ETOPO_PROP_UNKNOWN = 3000, /* unknown topo prop error */ + ETOPO_PROP_NOENT, /* undefined property or property group */ + ETOPO_PROP_DEFD, /* static property already defined */ + ETOPO_PROP_NOMEM, /* memory limit exceeded during property allocation */ + ETOPO_PROP_TYPE, /* invalid property type */ + ETOPO_PROP_NAME, /* invalid property name */ + ETOPO_PROP_NOINHERIT, /* can not inherit property */ + ETOPO_PROP_NVL, /* malformed property nvlist */ + ETOPO_PROP_METHOD, /* get property method failed */ + ETOPO_PROP_END /* end of prop errno list (to ease auto-merge) */ +} topo_prop_errno_t; + +typedef enum topo_method_errno { + ETOPO_METHOD_UNKNOWN = 3100, /* unknown topo method error */ + ETOPO_METHOD_INVAL, /* invalid method registration */ + ETOPO_METHOD_NOTSUP, /* method not supported */ + ETOPO_METHOD_FAIL, /* method failed */ + ETOPO_METHOD_VEROLD, /* app is compiled to use obsolete method */ + ETOPO_METHOD_VERNEW, /* app is compiled to use obsolete method */ + ETOPO_METHOD_NOMEM, /* memory limit exceeded during method op */ + ETOPO_METHOD_DEFD, /* method op already defined */ + ETOPO_METHOD_END /* end of method errno list */ +} topo_method_errno_t; + +typedef enum topo_fmri_errno { + ETOPO_FMRI_UNKNOWN = 3200, /* unknown topo fmri error */ + ETOPO_FMRI_NVL, /* nvlist allocation failure for FMRI */ + ETOPO_FMRI_VERSION, /* invalid FMRI scheme version */ + ETOPO_FMRI_MALFORM, /* malformed FMRI */ + ETOPO_FMRI_NOMEM, /* memory limit exceeded */ + ETOPO_FMRI_END /* end of fmri errno list */ +} topo_fmri_errno_t; + +typedef enum topo_hdl_errno { + ETOPO_HDL_UNKNOWN = 3300, /* unknown topo handle error */ + ETOPO_HDL_ABIVER, /* handle opened with invalid ABI version */ + ETOPO_HDL_SNAP, /* snapshot already taken */ + ETOPO_HDL_INVAL, /* invalid argument specified */ + ETOPO_HDL_UUID, /* uuid already set */ + ETOPO_HDL_NOMEM, /* memory limit exceeded */ + ETOPO_HDL_END /* end of handle errno list */ +} topo_hdl_errno_t; + +extern const char *topo_strerror(int); +extern void topo_hdl_strfree(topo_hdl_t *, char *); +extern void topo_debug_set(topo_hdl_t *, const char *, const char *); + +/* + * The following functions and data structures to support property + * observability are private to the fmtopo command. + */ + +/* + * Each topology node advertises the name and data stability of each of its + * modules and properties. (see attributes(5)). + */ + +/* + * Topo stability attributes + */ +typedef enum topo_stability { + TOPO_STABILITY_UNKNOWN = 0, /* private to libtopo */ + TOPO_STABILITY_INTERNAL, /* private to libtopo */ + TOPO_STABILITY_PRIVATE, /* private to Sun */ + TOPO_STABILITY_OBSOLETE, /* scheduled for removal */ + TOPO_STABILITY_EXTERNAL, /* not controlled by Sun */ + TOPO_STABILITY_UNSTABLE, /* new or rapidly changing */ + TOPO_STABILITY_EVOLVING, /* less rapidly changing */ + TOPO_STABILITY_STABLE, /* mature interface from Sun */ + TOPO_STABILITY_STANDARD /* industry standard */ +} topo_stability_t; + +#define TOPO_STABILITY_MAX TOPO_STABILITY_STANDARD /* max valid stab */ + +typedef struct topo_pgroup_info { + const char *tpi_name; /* property group name */ + topo_stability_t tpi_namestab; /* stability of group name */ + topo_stability_t tpi_datastab; /* stability of all property values */ + topo_version_t tpi_version; /* version of pgroup definition */ +} topo_pgroup_info_t; + +extern topo_stability_t topo_name2stability(const char *); +extern const char *topo_stability2name(topo_stability_t); +extern void topo_pgroup_destroy(tnode_t *, const char *); +extern topo_pgroup_info_t *topo_pgroup_info(tnode_t *, const char *, int *); + +typedef enum { + TOPO_TYPE_INVALID = 0, + TOPO_TYPE_BOOLEAN, /* boolean */ + TOPO_TYPE_INT32, /* int32_t */ + TOPO_TYPE_UINT32, /* uint32_t */ + TOPO_TYPE_INT64, /* int64_t */ + TOPO_TYPE_UINT64, /* uint64_t */ + TOPO_TYPE_STRING, /* const char* */ + TOPO_TYPE_TIME, /* uint64_t */ + TOPO_TYPE_SIZE, /* uint64_t */ + TOPO_TYPE_FMRI, /* nvlist_t */ + TOPO_TYPE_INT32_ARRAY, /* array of int32_t */ + TOPO_TYPE_UINT32_ARRAY, /* array of uint32_t */ + TOPO_TYPE_INT64_ARRAY, /* array of int64_t */ + TOPO_TYPE_UINT64_ARRAY, /* array of uint64_t */ + TOPO_TYPE_STRING_ARRAY, /* array of const char* */ + TOPO_TYPE_FMRI_ARRAY /* array of nvlist_t */ +} topo_type_t; + +extern nvlist_t *topo_prop_getprops(tnode_t *, int *err); +extern int topo_prop_getprop(tnode_t *, const char *, const char *, + nvlist_t *, nvlist_t **, int *); +extern int topo_prop_getpgrp(tnode_t *, const char *, nvlist_t **, int *); +extern int topo_prop_setprop(tnode_t *, const char *, nvlist_t *, + int, nvlist_t *, int *); +extern int topo_fmri_getprop(topo_hdl_t *, nvlist_t *, const char *, + const char *, nvlist_t *, nvlist_t **, int *); +extern int topo_fmri_getpgrp(topo_hdl_t *, nvlist_t *, const char *, + nvlist_t **, int *); +extern int topo_fmri_setprop(topo_hdl_t *, nvlist_t *, const char *, + nvlist_t *, int, nvlist_t *, int *); + /* Property node NVL names used in topo_prop_getprops */ #define TOPO_PROP_GROUP "property-group" #define TOPO_PROP_GROUP_NAME "property-group-name" @@ -231,47 +288,22 @@ #define TOPO_PROP_VAL_NAME "property-name" #define TOPO_PROP_VAL_VAL "property-value" #define TOPO_PROP_VAL_TYPE "property-type" +#define TOPO_PROP_FLAG "property-flag" /* - * This enum definition is used to define a set of error tags associated with - * the libtopo various error conditions occuring during the adminstration of - * properties. The shell script mkerror.sh is - * used to parse this file and create a corresponding topo_error.c source file. - * If you do something other than add a new error tag here, you may need to - * update the mkerror shell script as it is based upon simple regexps. + * ARGS list used in topo property methods */ -typedef enum topo_prop_errno { - ETOPO_PROP_UNKNOWN = 3000, /* unknown topo prop error */ - ETOPO_PROP_NOENT, /* undefined property or property group */ - ETOPO_PROP_DEFD, /* static property already defined */ - ETOPO_PROP_NOMEM, /* memory limit exceeded during property allocation */ - ETOPO_PROP_TYPE, /* invalid property type */ - ETOPO_PROP_NOINHERIT, /* can not inherit property */ - ETOPO_PROP_NVL, /* malformed property nvlist */ - ETOPO_PROP_END /* end of prop errno list (to ease auto-merge) */ -} topo_prop_errno_t; +#define TOPO_PROP_ARGS "args" +#define TOPO_PROP_PARGS "private-args" -/* - * Similar to the above, this enum defines a set of errors associated with node - * methods. - */ -typedef enum topo_method_errno { - ETOPO_METHOD_UNKNOWN = 4000, /* unknown topo method error */ - ETOPO_METHOD_INVAL, /* invalid method registration */ - ETOPO_METHOD_NOTSUP, /* method not supported */ - ETOPO_METHOD_FAIL /* method failed */ -} topo_method_errno_t; +extern int topo_xml_print(topo_hdl_t *, FILE *, const char *scheme, int *); - -extern const char *topo_strerror(int); -extern void topo_debug_set(topo_hdl_t *, const char *, const char *); extern void *topo_hdl_alloc(topo_hdl_t *, size_t); extern void *topo_hdl_zalloc(topo_hdl_t *, size_t); extern void topo_hdl_free(topo_hdl_t *, void *, size_t); extern int topo_hdl_nvalloc(topo_hdl_t *, nvlist_t **, uint_t); extern int topo_hdl_nvdup(topo_hdl_t *, nvlist_t *, nvlist_t **); extern char *topo_hdl_strdup(topo_hdl_t *, const char *); -extern void topo_hdl_strfree(topo_hdl_t *, char *); #ifdef __cplusplus }
--- a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers Mon Apr 23 15:34:38 2007 -0700 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -35,10 +35,12 @@ topo_fmri_create; topo_fmri_expand; topo_fmri_fru; - topo_fmri_invoke; + topo_fmri_getpgrp; + topo_fmri_getprop; topo_fmri_label; topo_fmri_nvl2str; topo_fmri_present; + topo_fmri_setprop; topo_fmri_str2nvl; topo_fmri_unusable; topo_hdl_alloc; @@ -104,6 +106,7 @@ topo_open; topo_pgroup_create; topo_pgroup_destroy; + topo_pgroup_info; topo_prop_get_fmri; topo_prop_get_int32; topo_prop_get_int64; @@ -116,8 +119,11 @@ topo_prop_get_uint64_array; topo_prop_get_string_array; topo_prop_get_fmri_array; + topo_prop_getprop; topo_prop_getprops; topo_prop_inherit; + topo_prop_method_register; + topo_prop_method_unregister; topo_prop_set_fmri; topo_prop_set_int32; topo_prop_set_int64; @@ -130,6 +136,7 @@ topo_prop_set_uint64_array; topo_prop_set_string_array; topo_prop_set_fmri_array; + topo_prop_setprop; topo_name2stability; topo_stability2name; topo_snap_hold;
--- a/usr/src/lib/fm/topo/libtopo/common/mkerror.sh Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/mkerror.sh Mon Apr 23 15:34:38 2007 -0700 @@ -34,7 +34,7 @@ if [ $1 = "liberrors" ] ; then echo "\ /*\n\ - * Copyright 2007 Sun Microsystems, Inc. All rights reserved.\n\ + * Copyright 2006 Sun Microsystems, Inc. All rights reserved.\n\ * Use is subject to license terms.\n\ */\n\ \n\ @@ -111,6 +111,41 @@ \n\ static const int _topo_nmethoderrstrs =\n\ sizeof (_topo_methoderrstrs) / sizeof (_topo_methoderrstrs[0]);" + +elif [ $1 = "fmrierrors" ] ; then + +echo "\ +\n\ +static const char *const _topo_fmrierrstrs[] = {" + +pattern='^[ ]*ETOPO_FMRI_[A-Z0-9_]*.*\* \(.*\) \*.*' +replace=' "\1",' + +echo "$input" | sed -n "s/$pattern/$replace/p" || exit 1 + +echo "\ +};\n\ +\n\ +static const int _topo_nfmrierrstrs =\n\ + sizeof (_topo_fmrierrstrs) / sizeof (_topo_fmrierrstrs[0]);" + +elif [ $1 = "hdlerrors" ] ; then + +echo "\ +\n\ +static const char *const _topo_hdlerrstrs[] = {" + +pattern='^[ ]*ETOPO_HDL_[A-Z0-9_]*.*\* \(.*\) \*.*' +replace=' "\1",' + +echo "$input" | sed -n "s/$pattern/$replace/p" || exit 1 + +echo "\ +};\n\ +\n\ +static const int _topo_nhdlerrstrs =\n\ + sizeof (_topo_hdlerrstrs) / sizeof (_topo_hdlerrstrs[0]);" + else echo "\ @@ -162,7 +197,13 @@ s = _topo_properrstrs[err - ETOPO_PROP_UNKNOWN]; else if (err >= ETOPO_METHOD_UNKNOWN && (err - ETOPO_METHOD_UNKNOWN) < _topo_nmethoderrstrs) - s = _topo_methoderrstrs[err - ETOPO_METHOD_UNKNOWN]; + s = _topo_methoderrstrs[err - ETOPO_PROP_UNKNOWN]; + else if (err >= ETOPO_HDL_UNKNOWN && (err - ETOPO_HDL_UNKNOWN) < + _topo_nhdlerrstrs) + s = _topo_hdlerrstrs[err - ETOPO_PROP_UNKNOWN]; + else if (err >= ETOPO_FMRI_UNKNOWN && (err - ETOPO_FMRI_UNKNOWN) < + _topo_nfmrierrstrs) + s = _topo_fmrierrstrs[err - ETOPO_PROP_UNKNOWN]; else s = _topo_errstrs[0];
--- a/usr/src/lib/fm/topo/libtopo/common/topo_error.h Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_error.h Mon Apr 23 15:34:38 2007 -0700 @@ -46,10 +46,6 @@ ETOPO_UNKNOWN = 1000, /* unknown libtopo error */ ETOPO_NOMEM, /* memory limit exceeded */ ETOPO_MODULE, /* module detected or caused an error */ - ETOPO_HDL_ABIVER, /* handle opened with invalid ABI version */ - ETOPO_HDL_SNAP, /* snapshot already taken */ - ETOPO_HDL_INVAL, /* invalid argument specified */ - ETOPO_HDL_UUID, /* uuid already set */ ETOPO_MOD_INIT, /* failed to initialize module */ ETOPO_MOD_FINI, /* failed to uninitialize module */ ETOPO_MOD_LOADED, /* specified module is already loaded */ @@ -81,9 +77,6 @@ ETOPO_ENUM_NOMAP, /* no topology map file for enumeration */ ETOPO_ENUM_FATAL, /* fatal enumeration error */ ETOPO_ENUM_RECURS, /* recursive enumertation detected */ - ETOPO_FMRI_NVL, /* nvlist allocation failure for FMRI */ - ETOPO_FMRI_VERSION, /* invalid FMRI scheme version */ - ETOPO_FMRI_MALFORM, /* malformed FMRI */ ETOPO_NVL_INVAL, /* invalid nvlist function argument */ ETOPO_FILE_NOENT, /* no topology file found */ ETOPO_PRSR_BADGRP, /* unrecognized grouping */
--- a/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c Mon Apr 23 15:34:38 2007 -0700 @@ -36,6 +36,35 @@ #include <topo_subr.h> #include <topo_string.h> +/* + * Topology node properties and method operations may be accessed by FMRI. + * The FMRI used to perform property look-ups and method operations is + * the FMRI contained in the matching topology node's protocol property + * grouping for the resource property. The full range of fmd(1M) + * scheme plugin operations are supported as long as a backend method is + * supplied by a scheme-specific enumerator or the enumerator module that + * created the matching topology node. Support for fmd scheme operations + * include: + * + * - expand + * - present + * - contains + * - unusable + * - nvl2str + * + * In addition, the following operations are supported per-FMRI: + * + * - str2nvl: convert string-based FMRI to nvlist + * - compare: compare two FMRIs + * - asru: lookup associated ASRU property by FMRI + * - fru: lookup associated FRU by FMRI + * - create: an FMRI nvlist by scheme type + * - propery lookup + * + * These routines may only be called by consumers of a topology snapshot. + * They may not be called by libtopo enumerator or method modules. + */ + /*ARGSUSED*/ static int set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) @@ -138,41 +167,14 @@ return (0); } -/* ARGSUSED */ -static int -is_present(topo_hdl_t *thp, tnode_t *node, void *data) -{ - int err; - uint32_t present = 0; - nvlist_t *out = NULL; - nvlist_t *fmri = (nvlist_t *)data; - - if (topo_method_invoke(node, TOPO_METH_PRESENT, - TOPO_METH_PRESENT_VERSION, fmri, &out, &err) < 0) { - if (out != NULL) - nvlist_free(out); - return (present); - } - - (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present); - - nvlist_free(out); - - return (present); -} - int topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) { - int ret = 0; uint32_t present = 0; char *scheme; nvlist_t *out = NULL; tnode_t *rnode; - if (topo_fmri_invoke(thp, fmri, is_present, fmri, &ret) == 0) - return (ret); - if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) return (set_error(thp, ETOPO_FMRI_MALFORM, err, TOPO_METH_PRESENT, out)); @@ -196,37 +198,43 @@ int topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) { - int rc; + uint32_t contains; char *scheme; - nvlist_t *in, *out = NULL; + nvlist_t *in = NULL, *out = NULL; tnode_t *rnode; if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) return (set_error(thp, ETOPO_FMRI_MALFORM, err, - TOPO_METH_CONTAINS, out)); + TOPO_METH_CONTAINS, NULL)); if ((rnode = topo_hdl_root(thp, scheme)) == NULL) return (set_error(thp, ETOPO_METHOD_NOTSUP, err, - TOPO_METH_CONTAINS, out)); + TOPO_METH_CONTAINS, NULL)); if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, - out)); + NULL)); - if (nvlist_add_nvlist(in, "fmri", fmri) != 0 || - nvlist_add_nvlist(in, "subfmri", subfmri) != 0) + if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 || + nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0) return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, - out)); + in)); if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0) return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, out)); - if ((rc = topo_method_invoke(rnode, TOPO_METH_CONTAINS, - TOPO_METH_CONTAINS_VERSION, fmri, &out, err)) < 0) - return (set_error(thp, *err, err, TOPO_METH_CONTAINS, out)); + if (topo_method_invoke(rnode, TOPO_METH_CONTAINS, + TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) { + nvlist_free(out); + return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in)); + } - return (rc); + (void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains); + nvlist_free(in); + nvlist_free(out); + + return (contains); } int @@ -277,175 +285,220 @@ return (0); } -struct prop_lookup { - int pl_err; - topo_type_t pl_type; - const char *pl_group; - const char *pl_name; - nvlist_t **pl_prop; - nvlist_t *pl_resource; -}; - static int -prop_lookup(topo_hdl_t *thp, tnode_t *node, void *pdata) +fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, + const char *pname, nvlist_t *args, nvlist_t **prop, + int *err) { - int rc; - nvlist_t *r1; - struct prop_lookup *plp = (struct prop_lookup *)pdata; - - if (topo_node_resource(node, &r1, &plp->pl_err) != 0) - return (TOPO_WALK_ERR); + int rv; + nvlist_t *in = NULL; + tnode_t *rnode; + char *scheme; - rc = topo_fmri_compare(thp, r1, plp->pl_resource, &plp->pl_err); - nvlist_free(r1); - if (rc == 0) - return (TOPO_WALK_NEXT); - if (rc < 0) - return (TOPO_WALK_ERR); + if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_PROP_GET, in)); - /* - * Special case for dynamically created ASRU and FRU - */ - if (strcmp(plp->pl_group, TOPO_PGROUP_PROTOCOL) == 0) { - if (strcmp(plp->pl_name, TOPO_PROP_ASRU) == 0) { - if (topo_node_asru(node, plp->pl_prop, plp->pl_resource, - &plp->pl_err) < 0) { - return (TOPO_WALK_ERR); - } - return (0); - } else if (strcmp(plp->pl_name, TOPO_PROP_FRU) == 0) { - if (topo_node_fru(node, plp->pl_prop, plp->pl_resource, - &plp->pl_err) < 0) { - return (TOPO_WALK_ERR); - } - return (0); - } - } + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_PROP_GET, in)); - switch (plp->pl_type) { - case TOPO_TYPE_STRING: - { - char *str; - if (topo_prop_get_string(node, plp->pl_group, - plp->pl_name, &str, &plp->pl_err) < 0) - return (TOPO_WALK_ERR); + if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_PROP_GET, in)); - if (nvlist_add_string(*plp->pl_prop, "prop", str) - != 0) { - topo_hdl_strfree(thp, str); - plp->pl_err = ETOPO_PROP_NVL; - return (TOPO_WALK_ERR); - } - topo_hdl_strfree(thp, str); - return (TOPO_WALK_TERMINATE); - } - default: - plp->pl_err = ETOPO_PROP_TYPE; - return (TOPO_WALK_ERR); - } - -} - -static int -fmri_prop(topo_hdl_t *thp, nvlist_t *resource, const char *pgname, - const char *pname, topo_type_t type, nvlist_t **prop, int *err) -{ - int rc; - topo_walk_t *wp; - char *scheme; - struct prop_lookup pl; - - if (nvlist_lookup_string(resource, FM_FMRI_SCHEME, &scheme) != 0) - return (set_error(thp, ETOPO_METHOD_INVAL, err, - "fmri_prop", NULL)); + rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); + rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); + rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname); + if (args != NULL) + rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); + if (rv != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_PROP_GET, in)); *prop = NULL; - pl.pl_resource = resource; - pl.pl_err = 0; - pl.pl_type = type; - pl.pl_group = pgname; - pl.pl_name = pname; - pl.pl_prop = prop; - if ((wp = topo_walk_init(thp, scheme, prop_lookup, &pl, err)) == NULL) - return (set_error(thp, pl.pl_err, err, "fmri_prop", NULL)); + rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET, + TOPO_METH_PROP_GET_VERSION, in, prop, err); - rc = topo_walk_step(wp, TOPO_WALK_CHILD); - topo_walk_fini(wp); + nvlist_free(in); - if (rc == TOPO_WALK_ERR) { - return (set_error(thp, pl.pl_err, err, "fmri_prop", NULL)); - } + if (rv != 0) + return (-1); /* *err is set for us */ - /* - * Walk terminated without finding resource or property - */ if (*prop == NULL) - return (set_error(thp, ETOPO_PROP_NOENT, err, "fmri_prop", - NULL)); - + return (set_error(thp, ETOPO_PROP_NOENT, err, + TOPO_METH_PROP_GET, NULL)); return (0); } int topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) { + nvlist_t *ap, *prop = NULL; if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, - TOPO_TYPE_FMRI, asru, err) < 0) + nvl, &prop, err) < 0) return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); + if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0) + return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru", + prop)); + + if (topo_hdl_nvdup(thp, ap, asru) < 0) + return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru", + prop)); + + nvlist_free(prop); + return (0); } int topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err) { + nvlist_t *fp, *prop = NULL; if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, - TOPO_TYPE_FMRI, fru, err) < 0) + nvl, fru, err) < 0) return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); + if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0) + return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru", + prop)); + + if (topo_hdl_nvdup(thp, fp, fru) < 0) + return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru", + prop)); + + nvlist_free(prop); + return (0); } int -topo_fmri_label(topo_hdl_t *thp, nvlist_t *fmri, char **label, int *err) +topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err) { - nvlist_t *nvl, *fru; - char *str; + nvlist_t *prop = NULL; + char *lp; - if (topo_fmri_fru(thp, fmri, &fru, err) < 0) + if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, + NULL, &prop, err) < 0) return (set_error(thp, *err, err, "topo_fmri_label", NULL)); - if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) + if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0) return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", - NULL)); + prop)); + + if ((*label = topo_hdl_strdup(thp, lp)) == NULL) + return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label", + prop)); + + nvlist_free(prop); + + return (0); +} + +int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, + const char *pname, nvlist_t *args, nvlist_t **prop, + int *err) +{ + *prop = NULL; + + return (fmri_prop(thp, nvl, pg, pname, args, prop, err)); +} - if (fmri_prop(thp, fru, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, - TOPO_TYPE_STRING, &nvl, err) < 0) { - nvlist_free(fru); - return (set_error(thp, *err, err, "topo_fmri_label", nvl)); - } +int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, + nvlist_t *prop, int flag, nvlist_t *args, int *err) +{ + int rv; + nvlist_t *in = NULL, *out = NULL; + tnode_t *rnode; + char *scheme; + + if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_PROP_SET, in)); + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_PROP_SET, in)); + + if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_PROP_SET, in)); + + rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl); + rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg); + rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop); + rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag); + if (args != NULL) + rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); + if (rv != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_PROP_SET, in)); - nvlist_free(fru); + rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET, + TOPO_METH_PROP_SET_VERSION, in, &out, err); + + nvlist_free(in); + + /* no return values */ + if (out != NULL) + nvlist_free(out); + + if (rv) + return (-1); - if (nvlist_lookup_string(nvl, "prop", &str) != 0) - return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", - nvl)); + return (0); + +} + +int +topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, + nvlist_t **pgroup, int *err) +{ + int rv; + nvlist_t *in = NULL; + tnode_t *rnode; + char *scheme; - if ((*label = topo_hdl_strdup(thp, str)) == NULL) - return (set_error(thp, ETOPO_PROP_NOMEM, err, - "topo_fmri_label", nvl)); + if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_PROP_GET, in)); + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_PROP_GET, in)); + + if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_PROP_GET, in)); - nvlist_free(nvl); + rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); + rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); + if (rv != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_PROP_GET, in)); + *pgroup = NULL; + rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET, + TOPO_METH_PGRP_GET_VERSION, in, pgroup, err); + + nvlist_free(in); + + if (rv != 0) + return (-1); /* *err is set for us */ + + if (*pgroup == NULL) + return (set_error(thp, ETOPO_PROP_NOENT, err, + TOPO_METH_PROP_GET, NULL)); return (0); } int topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) { - int rc; + uint32_t compare; char *scheme1, *scheme2; nvlist_t *in; nvlist_t *out = NULL; @@ -469,80 +522,20 @@ return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, NULL)); - if (nvlist_add_nvlist(in, "nv1", f1) != 0 || - nvlist_add_nvlist(in, "nv2", f2) != 0) + if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 || + nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0) return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, in)); - if ((rc = topo_method_invoke(rnode, TOPO_METH_COMPARE, - TOPO_METH_COMPARE_VERSION, in, &out, err)) < 0) + if (topo_method_invoke(rnode, TOPO_METH_COMPARE, + TOPO_METH_COMPARE_VERSION, in, &out, err) < 0) return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); + (void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare); + nvlist_free(out); nvlist_free(in); - return (rc); -} - -struct topo_invoke { - nvlist_t *tl_resource; - topo_walk_cb_t tl_func; - int tl_ret; - void *tl_pdata; -}; - -static int -walk_invoke(topo_hdl_t *thp, tnode_t *node, void *pdata) -{ - int rc; - struct topo_invoke *tlp = (struct topo_invoke *)pdata; - nvlist_t *r1, *r2 = tlp->tl_resource; - - if (topo_node_resource(node, &r1, &tlp->tl_ret) != 0) - return (TOPO_WALK_ERR); - - rc = topo_fmri_compare(thp, r1, r2, &tlp->tl_ret); - nvlist_free(r1); - if (rc == 0) - return (TOPO_WALK_NEXT); - else if (rc == -1) - return (TOPO_WALK_ERR); - - tlp->tl_ret = tlp->tl_func(thp, node, tlp->tl_pdata); - - return (TOPO_WALK_TERMINATE); -} - -int -topo_fmri_invoke(topo_hdl_t *thp, nvlist_t *nvl, topo_walk_cb_t cb_f, - void *pdata, int *ret) -{ - int err; - topo_walk_t *wp; - char *scheme; - struct topo_invoke tl; - - if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) - return (set_error(thp, ETOPO_METHOD_INVAL, ret, - "topo_fmri_invoke", NULL)); - - tl.tl_resource = nvl; - tl.tl_func = cb_f; - tl.tl_pdata = pdata; - tl.tl_ret = 0; - if ((wp = topo_walk_init(thp, scheme, walk_invoke, &tl, &err)) == NULL) - return (set_error(thp, err, ret, "topo_fmri_invoke", NULL)); - - err = topo_walk_step(wp, TOPO_WALK_CHILD); - topo_walk_fini(wp); - - if (err == TOPO_WALK_ERR) { - *ret = err; - return (-1); - } - - *ret = tl.tl_ret; - - return (0); + return (compare); } /*
--- a/usr/src/lib/fm/topo/libtopo/common/topo_method.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_method.c Mon Apr 23 15:34:38 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -42,12 +42,11 @@ #include <topo_subr.h> #include <topo_tree.h> -static topo_imethod_t * +topo_imethod_t * topo_method_lookup(tnode_t *node, const char *name) { topo_imethod_t *mp; - topo_node_lock(node); for (mp = topo_list_next(&node->tn_methods); mp != NULL; mp = topo_list_next(mp)) { if (strcmp(name, mp->tim_name) == 0) { @@ -55,7 +54,6 @@ return (mp); } } - topo_node_unlock(node); return (NULL); } @@ -99,6 +97,8 @@ topo_mod_free(mod, mp, sizeof (topo_imethod_t)); } + topo_node_unlock(node); + topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "method registration failed for %s: %s\n", mod->tm_name, topo_strerror(err)); @@ -117,8 +117,11 @@ */ for (meth = &mp[0]; meth->tm_name != NULL; meth++) { - if (topo_method_lookup(node, meth->tm_name) != NULL) + topo_node_lock(node); + if (topo_method_lookup(node, meth->tm_name) != NULL) { + topo_node_unlock(node); continue; + } if (meth->tm_stability < TOPO_STABILITY_INTERNAL || meth->tm_stability > TOPO_STABILITY_MAX || @@ -129,17 +132,17 @@ imp = topo_mod_zalloc(mod, sizeof (topo_imethod_t)); if (imp == NULL) return (set_methregister_error(mod, node, imp, - ETOPO_NOMEM)); + ETOPO_METHOD_NOMEM)); if ((imp->tim_name = topo_mod_strdup(mod, meth->tm_name)) == NULL) return (set_methregister_error(mod, node, imp, - ETOPO_NOMEM)); + ETOPO_METHOD_NOMEM)); if ((imp->tim_desc = topo_mod_strdup(mod, meth->tm_desc)) == NULL) return (set_methregister_error(mod, node, imp, - ETOPO_NOMEM)); + ETOPO_METHOD_NOMEM)); imp->tim_stability = meth->tm_stability; @@ -147,7 +150,6 @@ imp->tim_func = meth->tm_func; imp->tim_mod = mod; - topo_node_lock(node); topo_list_append(&node->tn_methods, imp); topo_node_unlock(node); @@ -208,25 +210,22 @@ int -topo_method_invoke(tnode_t *node, const char *method, +topo_method_call(tnode_t *node, const char *method, topo_version_t version, nvlist_t *in, nvlist_t **out, int *err) { int rc; topo_imethod_t *mp; - topo_node_hold(node); for (mp = topo_list_next(&node->tn_methods); mp != NULL; mp = topo_list_next(mp)) { if (strcmp(method, mp->tim_name) != 0) continue; if (version < mp->tim_version) { - *err = ETOPO_VER_NEW; - topo_node_rele(node); + *err = ETOPO_METHOD_VERNEW; return (-1); } else if (version > mp->tim_version) { - *err = ETOPO_VER_OLD; - topo_node_rele(node); + *err = ETOPO_METHOD_VEROLD; return (-1); } @@ -240,14 +239,23 @@ } topo_method_exit(mp); - topo_node_rele(node); - return (rc); } - topo_node_rele(node); *err = ETOPO_METHOD_NOTSUP; - return (-1); } + +int +topo_method_invoke(tnode_t *node, const char *method, + topo_version_t version, nvlist_t *in, nvlist_t **out, int *err) +{ + int rc; + + topo_node_hold(node); + rc = topo_method_call(node, method, version, in, out, err); + topo_node_rele(node); + + return (rc); +}
--- a/usr/src/lib/fm/topo/libtopo/common/topo_method.h Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_method.h Mon Apr 23 15:34:38 2007 -0700 @@ -33,6 +33,28 @@ extern "C" { #endif +#include <topo_list.h> + +typedef struct topo_imethod { + topo_list_t tim_list; /* next/prev pointers */ + pthread_mutex_t tim_lock; /* method entry lock */ + pthread_cond_t tim_cv; /* method entry cv */ + uint_t tim_busy; /* method entry busy indicator */ + char *tim_name; /* Method name */ + topo_version_t tim_version; /* Method version */ + topo_stability_t tim_stability; /* SMI stability of method */ + char *tim_desc; /* Method description */ + topo_method_f *tim_func; /* Method function */ + struct topo_mod *tim_mod; /* Ptr to controlling module */ +} topo_imethod_t; + +extern int topo_method_call(tnode_t *, const char *, topo_version_t, nvlist_t *, + nvlist_t **, int *); +extern topo_imethod_t *topo_method_lookup(tnode_t *, const char *); +extern int topo_prop_method_version_register(tnode_t *, const char *, + const char *, topo_type_t, const char *, topo_version_t, const nvlist_t *, + int *); + /* * FMRI methods */ @@ -43,6 +65,9 @@ #define TOPO_METH_STR2NVL "topo_str2nvl" #define TOPO_METH_CONTAINS "topo_contains" #define TOPO_METH_COMPARE "topo_compare" +#define TOPO_METH_PROP_GET "topo_prop_get" +#define TOPO_METH_PGRP_GET "topo_pgrp_get" +#define TOPO_METH_PROP_SET "topo_prop_set" #define TOPO_METH_FMRI_VERSION 0 #define TOPO_METH_FRU_COMPUTE_VERSION 0 @@ -51,14 +76,23 @@ #define TOPO_METH_STR2NVL_VERSION 0 #define TOPO_METH_CONTAINS_VERSION 0 #define TOPO_METH_COMPARE_VERSION 0 +#define TOPO_METH_PROP_GET_VERSION 0 +#define TOPO_METH_PGRP_GET_VERSION 0 +#define TOPO_METH_PROP_SET_VERSION 0 -#define TOPO_METH_ASRU_COMPUTE_DESC "Dynamic ASRU constructor" -#define TOPO_METH_FRU_COMPUTE_DESC "Dynamic FRU constructor" -#define TOPO_METH_FMRI_DESC "Dynamic FMRI constructor" -#define TOPO_METH_NVL2STR_DESC "FMRI to string" -#define TOPO_METH_STR2NVL_DESC "string to FMRI" -#define TOPO_METH_CONTAINS_DESC "FMRI contains sub-FMRI" -#define TOPO_METH_COMPARE_DESC "compare two FMRIs" +#define TOPO_METH_ASRU_COMPUTE_DESC "Dynamic ASRU constructor" +#define TOPO_METH_FRU_COMPUTE_DESC "Dynamic FRU constructor" +#define TOPO_METH_FMRI_DESC "Dynamic FMRI constructor" +#define TOPO_METH_NVL2STR_DESC "FMRI to string" +#define TOPO_METH_STR2NVL_DESC "string to FMRI" +#define TOPO_METH_CONTAINS_DESC "FMRI contains sub-FMRI" +#define TOPO_METH_COMPARE_DESC "compare two FMRIs" +#define TOPO_METH_PROP_GET_DESC "get properties for FMRI" +#define TOPO_METH_PGRP_GET_DESC "get property group for FMRI" +#define TOPO_METH_PROP_SET_DESC "set properties for FMRI" + +#define TOPO_METH_COMPARE_RET "contains-return" +#define TOPO_METH_CONTAINS_RET "contains-return" #define TOPO_METH_FMRI_ARG_NAME "child-name" #define TOPO_METH_FMRI_ARG_INST "child-inst" @@ -69,6 +103,10 @@ #define TOPO_METH_FMRI_ARG_REV "rev" #define TOPO_METH_FMRI_ARG_SER "serial" #define TOPO_METH_FMRI_ARG_HCS "hc-specific" +#define TOPO_METH_FMRI_ARG_FMRI "fmri" +#define TOPO_METH_FMRI_ARG_SUBFMRI "sub-fmri" +#define TOPO_METH_FMRI_ARG_NV1 "nv1" +#define TOPO_METH_FMRI_ARG_NV2 "nv2" #ifdef __cplusplus }
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c Mon Apr 23 15:34:38 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,11 +29,15 @@ * Topology Plugin Modules * * Topology plugin modules are shared libraries that are dlopen'd and - * used to enumerate resources in the system. - * They are loaded by our builtin scheme-specific plugins or other modules - * to enumerate and create nodes for resources that are present in the system. - * They may also export a set of resource (node) specific methods that can be - * called on node-by-node basis. + * used to enumerate resources in the system and export per-node method + * operations. + * + * They are loaded by our builtin scheme-specific plugins, other modules or + * by processing a topo map XML file to enumerate and create nodes for + * resources that are present in the system. They may also export a set of + * topology node specific methods that can be invoked directly via + * topo_method_invoke() or indirectly via the + * topo_prop_get* family of functions to access dynamic property data. * * Module Plugin API * @@ -45,20 +49,39 @@ * * In its enumeration callback routine, the module should search for resources * within its realm of resposibility and create any node ranges, - * topo_node_range_create() or nodes, topo_node_bind(). The Enumerator + * topo_node_range_create() and nodes, topo_node_bind(). The Enumerator * module is handed a node to which it may begin attaching additional - * topology nodes. + * topology nodes. The enumerator may only access those nodes within its + * current scope of operation: the node passed into its enumeration op and + * any nodes it creates during enumeration. If the enumerator requires walker- + * style access to these nodes, it must use + * topo_mod_walk_init()/topo_walk_step()/topo_walk_fini(). * * If additional helper modules need to be loaded to complete the enumeration * the module may do so by calling topo_mod_load(). Enumeration may then * continue with the module handing off enumeration to its helper module - * by calling topo_mod_enumerate(). + * by calling topo_mod_enumerate(). Similarly, a module may call + * topo_mod_enummap() to kick-off enumeration according to a given XML + * topology map file. A module *may* not cause re-entrance to itself + * via either of these interfaces. If re-entry is detected an error + * will be returned (ETOPO_ENUM_RECURS). * * If the module registers a release callback, it will be called on a node * by node basis during topo_snap_rele(). Any private node data may be * deallocated or methods unregistered at that time. Global module data - * should be clean-up before or at the time that the module _topo_fini + * should be cleaned up before or at the time that the module _topo_fini * entry point is called. + * + * Module entry points and method invocations are guaranteed to be + * single-threaded for a given snapshot handle. Applications may have + * more than one topology snapshot open at a time. This means that the + * module operations and methods may be called for different module handles + * (topo_mod_t) asynchronously. The enumerator should not use static or + * global data structures that may become inconsistent in this situation. + * Method operations may be re-entrant if the module invokes one of its own + * methods directly or via dynamic property access. Caution should be + * exercised with method operations to insure that data remains consistent + * within the module and that deadlocks can not occur. */ #include <pthread.h> @@ -157,7 +180,7 @@ if (version != TOPO_VERSION) return (set_register_error(mod, EMOD_VER_ABI)); - if ((mod->tm_info = topo_mod_alloc(mod, sizeof (topo_imodinfo_t))) + if ((mod->tm_info = topo_mod_zalloc(mod, sizeof (topo_imodinfo_t))) == NULL) return (set_register_error(mod, EMOD_NOMEM)); if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod, @@ -725,3 +748,17 @@ return (auth); } + +topo_walk_t * +topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f, + void *pdata, int *errp) +{ + topo_walk_t *wp; + topo_hdl_t *thp = mod->tm_hdl; + + if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata, + errp)) == NULL) + return (NULL); + + return (wp); +}
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h Mon Apr 23 15:34:38 2007 -0700 @@ -97,6 +97,14 @@ extern int topo_mod_str2nvl(topo_mod_t *, const char *, nvlist_t **); /* + * Snapshot walker support + */ +typedef int (*topo_mod_walk_cb_t)(topo_mod_t *, tnode_t *, void *); + +extern topo_walk_t *topo_mod_walk_init(topo_mod_t *, tnode_t *, + topo_mod_walk_cb_t, void *, int *); + +/* * Flags for topo_mod_memfmri */ #define TOPO_MEMFMRI_PA 0x0001 /* Valid physical address */ @@ -114,20 +122,20 @@ * FMRI methods */ #define TOPO_METH_LABEL "topo_label" -#define TOPO_METH_LABEL_DESC "Dynamic label discovery" +#define TOPO_METH_LABEL_DESC "label constructor" #define TOPO_METH_LABEL_VERSION0 0 #define TOPO_METH_LABEL_VERSION TOPO_METH_LABEL_VERSION0 #define TOPO_METH_LABEL_ARG_NVL "label-specific" #define TOPO_METH_LABEL_RET_STR "label-string" #define TOPO_METH_PRESENT "topo_present" -#define TOPO_METH_PRESENT_DESC "Dynamic label discovery" +#define TOPO_METH_PRESENT_DESC "presence indicator" #define TOPO_METH_PRESENT_VERSION0 0 #define TOPO_METH_PRESENT_VERSION TOPO_METH_PRESENT_VERSION0 #define TOPO_METH_PRESENT_RET "present-ret" #define TOPO_METH_UNUSABLE "topo_unusable" -#define TOPO_METH_UNUSABLE_DESC "FMRI is unusable" +#define TOPO_METH_UNUSABLE_DESC "unusable indicator" #define TOPO_METH_UNUSABLE_VERSION0 0 #define TOPO_METH_UNUSABLE_VERSION TOPO_METH_UNUSABLE_VERSION0 #define TOPO_METH_UNUSABLE_RET "unusable-ret" @@ -178,6 +186,43 @@ #define TOPO_FRU_COMPUTE 0x0002 /* Compute FRU dynamically */ /* + * Topo property set functions + */ +extern int topo_prop_set_int32(tnode_t *, const char *, const char *, int, + int32_t, int *); +extern int topo_prop_set_uint32(tnode_t *, const char *, const char *, int, + uint32_t, int *); +extern int topo_prop_set_int64(tnode_t *, const char *, const char *, + int, int64_t, int *); +extern int topo_prop_set_uint64(tnode_t *, const char *, const char *, + int, uint64_t, int *); +extern int topo_prop_set_string(tnode_t *, const char *, const char *, + int, const char *, int *); +extern int topo_prop_set_fmri(tnode_t *, const char *, const char *, + int, const nvlist_t *, int *); +extern int topo_prop_set_int32_array(tnode_t *, const char *, const char *, int, + int32_t *, uint_t, int *); +extern int topo_prop_set_uint32_array(tnode_t *, const char *, const char *, + int, uint32_t *, uint_t, int *); +extern int topo_prop_set_int64_array(tnode_t *, const char *, const char *, + int, int64_t *, uint_t, int *); +extern int topo_prop_set_uint64_array(tnode_t *, const char *, const char *, + int, uint64_t *, uint_t, int *); +extern int topo_prop_set_string_array(tnode_t *, const char *, const char *, + int, const char **, uint_t, int *); +extern int topo_prop_set_fmri_array(tnode_t *, const char *, const char *, + int, const nvlist_t **, uint_t, int *); +extern int topo_prop_inherit(tnode_t *, const char *, const char *, int *); +extern int topo_pgroup_create(tnode_t *, const topo_pgroup_info_t *, int *); + +/* + * Topo property method registration + */ +extern int topo_prop_method_register(tnode_t *, const char *, const char *, + topo_type_t, const char *, const nvlist_t *, int *); +extern void topo_prop_method_unregister(tnode_t *, const char *, const char *); + +/* * This enum definition is used to define a set of error tags associated with * the module api error conditions. The shell script mkerror.sh is * used to parse this file and create a corresponding topo_error.c source file.
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.map Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.map Mon Apr 23 15:34:38 2007 -0700 @@ -1,5 +1,5 @@ # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START @@ -70,4 +70,21 @@ topo_method_unregister_all = FUNCTION extern; topo_method_invoke = FUNCTION extern; + topo_prop_method_register = FUNCTION extern; + topo_prop_method_unregister = FUNCTION extern; + topo_prop_set_int32 = FUNCTION extern; + topo_prop_set_uint32 = FUNCTION extern; + topo_prop_set_int64 = FUNCTION extern; + topo_prop_set_uint64 = FUNCTION extern; + topo_prop_set_string = FUNCTION extern; + topo_prop_set_fmri = FUNCTION extern; + topo_prop_set_int32_array = FUNCTION extern; + topo_prop_set_uint32_array = FUNCTION extern; + topo_prop_set_int64_array = FUNCTION extern; + topo_prop_set_uint64_array = FUNCTION extern; + topo_prop_set_string_array = FUNCTION extern; + topo_prop_set_fmri_array = FUNCTION extern; + topo_prop_inherit = FUNCTION extern; + topo_pgroup_create = FUNCTION extern; + };
--- a/usr/src/lib/fm/topo/libtopo/common/topo_module.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_module.c Mon Apr 23 15:34:38 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -223,6 +223,8 @@ if ((mod = topo_hdl_zalloc(thp, sizeof (topo_mod_t))) == NULL) return (set_create_error(thp, mod, path, ETOPO_NOMEM)); + mod->tm_hdl = thp; + (void) pthread_mutex_init(&mod->tm_lock, NULL); mod->tm_name = topo_hdl_strdup(thp, name); @@ -233,7 +235,6 @@ return (set_create_error(thp, mod, path, ETOPO_NOMEM)); mod->tm_mops = (topo_imodops_t *)ops; - mod->tm_hdl = thp; mod->tm_alloc = thp->th_alloc; /* @@ -376,6 +377,9 @@ topo_modhash_t *mhp = thp->th_modhash; topo_mod_t *mp, **pp; + if (mhp == NULL) + return; + topo_modhash_lock(mhp); for (i = 0; i < TOPO_HASH_BUCKETS; ++i) { pp = &mhp->mh_hash[i];
--- a/usr/src/lib/fm/topo/libtopo/common/topo_node.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_node.c Mon Apr 23 15:34:38 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,17 +39,23 @@ * may change at anytime and are protected by a per-property locking * strategy. * - * Enumerator plugin modules may also safely access node data. Enumeration - * occurs only during topo_snap_hold() where a per-topo_hdl_t lock prevents - * multi-threaded access to the topology trees. + * Enumerator plugin modules may also safely access topology nodes within their + * scope of operation: the parent node passed into the enumeration op or those + * nodes created by the enumerator. Enumeration occurs only during + * topo_snap_hold() where a per-topo_hdl_t lock prevents multi-threaded access + * to the topology trees. * - * Like tree walking functions, method plugin modules have access to read-only - * node data but may make changes to property information. + * Enumerator method operation functions may safely access and change topology + * node property data, and contruct or destroy child nodes for the node + * on which the operation applies. The method may also be called to destroy + * the node for which the method operation is called. This permits + * dynamic topology tree snapshots and partial enumerations for branches that + * may not be needed right away. * * Node Interfaces * - * Nodes are created when an enumerator calls topo_node_bind(). Prior to the - * call to topo_node_bind(), the caller should have reserved a range of + * Nodes are created when an enumerator calls topo_node_bind(). Prior to + * calling topo_node_bind(), the enumerator should have reserved a range of * node instances with topo_node_range_create(). topo_node_range_create() * does not allocate any node resources but creates the infrastruture * required for a fully populated topology level. This allows enumerators @@ -58,19 +64,36 @@ * plugin. Only when the resource has been confirmed to exist should * the node be bound. * - * Node range and node linkage is only performed during enumeration when it - * is safe to change node hash lists and next pointers. Nodes and node ranges - * are deallocated when all references to the node have been released: + * Node range and node linkage and unlinkage is performed during enumeration and + * method operations when it is safe to change node hash lists. Nodes and node + * ranges are deallocated when all references to the node have been released: * last walk completes and topo_snap_rele() is called. * * Node Hash/Ranges * * Each parent node may have one or more ranges of child nodes. Each range - * serves as a hash list of like sibling nodes all with the same name but + * is uniquely named and serves as a hash list of like sibling nodes with * different instance numbers. A parent may have more than one node hash * (child range). If that is the case, the hash lists are strung together to * form sibling relationships between ranges. Hash/Ranges are sparsely * populated with only nodes that have represented resources in the system. + * + * _________________ + * | | + * | tnode_t | ----------------------------- + * | tn_phash ---> | topo_nodehash_t | + * | (children)| | th_nodearr (instances)| + * ----------------- | ------------------- | + * | ---| 0 | 1 | ...| N | | + * | | ------------------- | ------------------- + * | | th_list (siblings) ----->| topo_nodehash_t | + * | | | ------------------- + * ---|------------------------- + * | + * v + * ----------- + * | tnode_t | + * ----------- */ #include <assert.h> @@ -516,3 +539,49 @@ { return (0); } + +topo_walk_t * +topo_node_walk_init(topo_hdl_t *thp, topo_mod_t *mod, tnode_t *node, + int (*cb_f)(), void *pdata, int *errp) +{ + tnode_t *child; + topo_walk_t *wp; + + topo_node_hold(node); + + if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) == NULL) { + *errp = ETOPO_NOMEM; + topo_node_rele(node); + return (NULL); + } + + /* + * If this is the root of the scheme tree, start with the first + * child + */ + topo_node_lock(node); + if (node->tn_state & TOPO_NODE_ROOT) { + if ((child = topo_child_first(node)) == NULL) { + /* Nothing to walk */ + *errp = ETOPO_WALK_EMPTY; + topo_node_unlock(node); + topo_node_rele(node); + return (NULL); + } + topo_node_unlock(node); + topo_node_hold(child); + wp->tw_node = child; + } else { + topo_node_unlock(node); + topo_node_hold(child); + wp->tw_node = node; + } + + wp->tw_root = node; + wp->tw_cb = cb_f; + wp->tw_pdata = pdata; + wp->tw_thp = thp; + wp->tw_mod = mod; + + return (wp); +}
--- a/usr/src/lib/fm/topo/libtopo/common/topo_prop.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_prop.c Mon Apr 23 15:34:38 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,6 +32,47 @@ #include <topo_string.h> #include <topo_alloc.h> #include <topo_error.h> +#include <topo_method.h> + +/* + * Topology nodes are permitted to contain property information. + * Property information is organized according to property grouping. + * Each property group defines a name, a stability level for that name, + * a stability level for all underlying property data (name, type, values), + * a version for the property group definition and and a list of uniquely + * defined properties. Property group versions are incremented when one of + * the following changes occurs: + * - a property name changes + * - a property type changes + * - a property definition is removed from the group + * Compatible changes such as new property definitions in the group do + * not require version changes. + * + * Each property defines a unique (within the group) name, a type and + * a value. Properties may be statically defined as int32, uint32, int64, + * uint64, fmri, string or arrays of each type. Properties may also be + * dynamically exported via module registered methods. For example, a module + * may register a method to export an ASRU property that is dynamically + * contructed when a call to topo_node_fmri() is invoked for a particular + * topology node. + * + * Static properties are persistently attached to topology nodes during + * enumeration by an enumeration module or as part of XML statements in a + * toplogy map file using the topo_prop_set* family of routines. Similarly, + * property methods are registered during enumeration or as part of + * statements in topololgy map files. Set-up of property methods is performed + * by calling topo_prop_method_register(). + * + * All properties, whether statically persisted in a snapshot or dynamically + * obtained, may be read via the topo_prop_get* family of interfaces. + * Callers wishing to receive all property groups and properties for a given + * node may use topo_prop_getall(). This routine returns a nested nvlist + * of all groupings and property (name, type, value) sets. Groupings + * are defined by TOPO_PROP_GROUP (name, data stability, name stability and + * version) and a nested nvlist of properties (TOPO_PROP_VAL). Each property + * value is defined by its name, type and value. + */ +static void topo_propval_destroy(topo_propval_t *); static topo_pgroup_t * pgroup_get(tnode_t *node, const char *pgname) @@ -55,6 +96,9 @@ { topo_proplist_t *pvl; + if (pg == NULL) + return (NULL); + for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; pvl = topo_list_next(pvl)) { if (strcmp(pvl->tp_pval->tp_name, pname) == 0) @@ -64,254 +108,79 @@ return (NULL); } +static int +method_geterror(nvlist_t *nvl, int err, int *errp) +{ + if (nvl != NULL) + nvlist_free(nvl); + + *errp = err; + + return (-1); +} + +static int +prop_method_get(tnode_t *node, topo_propval_t *pv, topo_propmethod_t *pm, + nvlist_t *pargs, int *err) +{ + int ret; + nvlist_t *args, *nvl; + char *name; + topo_type_t type; + + if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0 || + nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args) != 0) + return (method_geterror(NULL, ETOPO_PROP_NVL, err)); + + if (pargs != NULL) + if (nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs) != 0) + return (method_geterror(args, ETOPO_PROP_NVL, err)); + + /* Now, get the latest value */ + if (topo_method_call(node, pm->tpm_name, pm->tpm_version, + args, &nvl, err) < 0) + return (method_geterror(args, *err, err)); + + nvlist_free(args); + + /* Verify the property contents */ + ret = nvlist_lookup_string(nvl, TOPO_PROP_VAL_NAME, &name); + if (ret != 0 || strcmp(name, pv->tp_name) != 0) + return (method_geterror(nvl, ETOPO_PROP_NAME, err)); + + ret = nvlist_lookup_uint32(nvl, TOPO_PROP_VAL_TYPE, (uint32_t *)&type); + if (ret != 0 || type != pv->tp_type) + return (method_geterror(nvl, ETOPO_PROP_TYPE, err)); + + /* Release the last value and re-assign to the new value */ + if (pv->tp_val != NULL) + nvlist_free(pv->tp_val); + pv->tp_val = nvl; + + return (0); +} + static topo_propval_t * -topo_prop_get(tnode_t *node, const char *pgname, const char *pname, int *err) +prop_get(tnode_t *node, const char *pgname, const char *pname, nvlist_t *pargs, + int *err) { - topo_pgroup_t *pg = NULL; topo_propval_t *pv = NULL; - if ((pg = pgroup_get(node, pgname)) == NULL) { + if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) { *err = ETOPO_PROP_NOENT; return (NULL); } - if ((pv = propval_get(pg, pname)) == NULL) { - *err = ETOPO_PROP_NOENT; - return (NULL); + if (pv->tp_method != NULL) { + if (prop_method_get(node, pv, pv->tp_method, pargs, err) < 0) + return (NULL); } return (pv); } static int -prop_val_add(nvlist_t *nvl, topo_propval_t *pv, int *err) -{ - int ret = 0; - uint_t nelems; - - if (nvlist_add_int32(nvl, TOPO_PROP_VAL_TYPE, pv->tp_type) != 0) - return (-1); - - switch (pv->tp_type) { - case TOPO_TYPE_INT32: - { - int32_t val; - if ((ret = nvlist_lookup_int32(pv->tp_val, - TOPO_PROP_VAL_VAL, &val)) < 0) - break; - ret = nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, val); - } - break; - case TOPO_TYPE_UINT32: - { - uint32_t val; - if ((ret = nvlist_lookup_uint32(pv->tp_val, - TOPO_PROP_VAL_VAL, &val)) < 0) - break; - ret = nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, val); - } - break; - case TOPO_TYPE_INT64: - { - int64_t val; - if ((ret = nvlist_lookup_int64(pv->tp_val, - TOPO_PROP_VAL_VAL, &val)) < 0) - break; - ret = nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, val); - } - break; - case TOPO_TYPE_UINT64: - { - uint64_t val; - if ((ret = nvlist_lookup_uint64(pv->tp_val, - TOPO_PROP_VAL_VAL, &val)) < 0) - break; - ret = nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, val); - } - break; - case TOPO_TYPE_STRING: - { - char *val; - if ((ret = nvlist_lookup_string(pv->tp_val, - TOPO_PROP_VAL_VAL, &val)) < 0) - break; - ret = nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, val); - } - break; - case TOPO_TYPE_FMRI: - { - nvlist_t *val; - if ((ret = nvlist_lookup_nvlist(pv->tp_val, - TOPO_PROP_VAL_VAL, &val)) < 0) - break; - ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, val); - } - break; - case TOPO_TYPE_INT32_ARRAY: - { - int32_t *val; - if ((ret = nvlist_lookup_int32_array(pv->tp_val, - TOPO_PROP_VAL_VAL, &val, &nelems)) < 0) - break; - ret = nvlist_add_int32_array(nvl, TOPO_PROP_VAL_VAL, - val, nelems); - } - break; - case TOPO_TYPE_UINT32_ARRAY: - { - uint32_t *val; - if ((ret = nvlist_lookup_uint32_array(pv->tp_val, - TOPO_PROP_VAL_VAL, &val, &nelems)) < 0) - break; - ret = nvlist_add_uint32_array(nvl, TOPO_PROP_VAL_VAL, - val, nelems); - } - break; - case TOPO_TYPE_INT64_ARRAY: - { - int64_t *val; - if ((ret = nvlist_lookup_int64_array(pv->tp_val, - TOPO_PROP_VAL_VAL, &val, &nelems)) < 0) - break; - ret = nvlist_add_int64_array(nvl, TOPO_PROP_VAL_VAL, - val, nelems); - } - break; - case TOPO_TYPE_UINT64_ARRAY: - { - uint64_t *val; - if ((ret = nvlist_lookup_uint64_array(pv->tp_val, - TOPO_PROP_VAL_VAL, &val, &nelems)) < 0) - break; - ret = nvlist_add_uint64_array(nvl, TOPO_PROP_VAL_VAL, - val, nelems); - } - break; - case TOPO_TYPE_STRING_ARRAY: - { - char **val; - if ((ret = nvlist_lookup_string_array(pv->tp_val, - TOPO_PROP_VAL_VAL, &val, &nelems)) < 0) - break; - ret = nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, - val, nelems); - } - break; - case TOPO_TYPE_FMRI_ARRAY: - { - nvlist_t **val; - if ((ret = nvlist_lookup_nvlist_array(pv->tp_val, - TOPO_PROP_VAL_VAL, &val, &nelems)) < 0) - break; - ret = nvlist_add_nvlist_array(nvl, TOPO_PROP_VAL_VAL, - val, nelems); - } - break; - default: - ret = ETOPO_PROP_TYPE; - } - - if (ret != 0) { - if (ret == ENOMEM) - *err = ETOPO_NOMEM; - else - *err = ETOPO_PROP_NVL; - return (-1); - } - - return (0); -} - -nvlist_t * -get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err) -{ - topo_node_unlock(node); - - if (nvl != NULL) - nvlist_free(nvl); - - *errp = err; - - return (NULL); -} - -nvlist_t * -topo_prop_getprops(tnode_t *node, int *err) -{ - int ret; - topo_hdl_t *thp = node->tn_hdl; - nvlist_t *nvl, *pgnvl, *pvnvl; - topo_pgroup_t *pg; - topo_propval_t *pv; - topo_proplist_t *pvl; - - if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { - return (get_all_seterror(node, NULL, err, ETOPO_NOMEM)); - } - - topo_node_lock(node); - for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; - pg = topo_list_next(pg)) { - if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0) - return (get_all_seterror(node, nvl, err, ETOPO_NOMEM)); - - if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME, - pg->tpg_info->tpi_name) != 0 || - nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB, - topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 || - nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB, - topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 || - nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION, - pg->tpg_info->tpi_version) != 0) - return (get_all_seterror(node, nvl, err, - ETOPO_PROP_NVL)); - - for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; - pvl = topo_list_next(pvl)) { - - pv = pvl->tp_pval; - if (topo_hdl_nvalloc(thp, &pvnvl, 0) - != 0) { - nvlist_free(pgnvl); - return (get_all_seterror(node, nvl, err, - ETOPO_NOMEM)); - } - if ((ret = nvlist_add_string(pvnvl, TOPO_PROP_VAL_NAME, - pv->tp_name)) != 0) { - nvlist_free(pgnvl); - nvlist_free(pvnvl); - return (get_all_seterror(node, nvl, err, ret)); - } - if (prop_val_add(pvnvl, pv, err) < 0) { - nvlist_free(pgnvl); - nvlist_free(pvnvl); - return (get_all_seterror(node, nvl, err, ret)); - } - if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL, - pvnvl)) != 0) { - nvlist_free(pgnvl); - nvlist_free(pvnvl); - return (get_all_seterror(node, nvl, err, ret)); - } - - nvlist_free(pvnvl); - } - if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl)) - != 0) { - nvlist_free(pgnvl); - return (get_all_seterror(node, nvl, err, ret)); - } - - nvlist_free(pgnvl); - } - - topo_node_unlock(node); - - return (nvl); -} - -static int -get_seterror(tnode_t *node, int *errp, int err) +get_properror(tnode_t *node, int *errp, int err) { topo_node_unlock(node); *errp = err; @@ -327,12 +196,12 @@ topo_propval_t *pv; topo_node_lock(node); - if ((pv = topo_prop_get(node, pgname, pname, err)) + if ((pv = prop_get(node, pgname, pname, NULL, err)) == NULL) - return (get_seterror(node, err, *err)); + return (get_properror(node, err, *err)); if (pv->tp_type != type) - return (get_seterror(node, err, ETOPO_PROP_TYPE)); + return (get_properror(node, err, ETOPO_PROP_TYPE)); switch (type) { case TOPO_TYPE_INT32: @@ -356,8 +225,13 @@ ret = nvlist_lookup_string(pv->tp_val, TOPO_PROP_VAL_VAL, &str); - if (ret == 0) - *(char **)val = topo_hdl_strdup(thp, str); + if (ret == 0) { + char *s2; + if ((s2 = topo_hdl_strdup(thp, str)) == NULL) + ret = -1; + else + *(char **)val = s2; + } break; } case TOPO_TYPE_FMRI: { @@ -488,11 +362,11 @@ if (ret != 0) if (ret == ENOENT) - return (get_seterror(node, err, ETOPO_PROP_NOENT)); + return (get_properror(node, err, ETOPO_PROP_NOENT)); else if (ret < ETOPO_UNKNOWN) - return (get_seterror(node, err, ETOPO_PROP_NVL)); + return (get_properror(node, err, ETOPO_PROP_NVL)); else - return (get_seterror(node, err, ret)); + return (get_properror(node, err, ret)); topo_node_unlock(node); return (0); @@ -594,7 +468,7 @@ TOPO_TYPE_FMRI_ARRAY, nelem, err)); } -static int +static topo_propval_t * set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err) { topo_hdl_t *thp = node->tn_hdl; @@ -602,52 +476,40 @@ if (pvl != NULL) { pv = pvl->tp_pval; - if (pv != NULL) { - if (pv->tp_name != NULL) - topo_hdl_strfree(thp, pv->tp_name); - if (pv->tp_val != NULL) - nvlist_free(pv->tp_val); - topo_hdl_free(thp, pv, sizeof (topo_propval_t)); - } + topo_propval_destroy(pv); topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); } topo_node_unlock(node); *errp = err; - return (-1); + return (NULL); } -static int -topo_prop_set(tnode_t *node, const char *pgname, const char *pname, - topo_type_t type, int flag, void *val, int nelems, int *err) +static topo_propval_t * +prop_create(tnode_t *node, const char *pgname, const char *pname, + topo_type_t type, int flag, int *err) { - int ret, new_prop = 0; topo_hdl_t *thp = node->tn_hdl; topo_pgroup_t *pg; topo_propval_t *pv; topo_proplist_t *pvl; - topo_node_lock(node); - if ((pg = pgroup_get(node, pgname)) == NULL) - return (set_seterror(node, NULL, err, ETOPO_PROP_NOENT)); - /* * Replace existing prop value with new one */ + if ((pg = pgroup_get(node, pgname)) == NULL) + return (NULL); + if ((pv = propval_get(pg, pname)) != NULL) { if (pv->tp_type != type) return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE)); else if (pv->tp_flag == TOPO_PROP_IMMUTABLE) return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD)); + nvlist_free(pv->tp_val); pv->tp_val = NULL; } else { - /* - * Property values may be a shared resources among - * different nodes. We will allocate resources - * on a per-handle basis. - */ if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) == NULL) return (set_seterror(node, NULL, err, ETOPO_NOMEM)); @@ -664,79 +526,104 @@ pv->tp_type = type; pv->tp_hdl = thp; topo_prop_hold(pv); - new_prop++; + topo_list_append(&pg->tpg_pvals, pvl); } - if (topo_hdl_nvalloc(thp, &pv->tp_val, NV_UNIQUE_NAME) < 0) - return (set_seterror(node, pvl, err, ETOPO_PROP_NVL)); + return (pv); +} - ret = 0; +static int +topo_prop_set(tnode_t *node, const char *pgname, const char *pname, + topo_type_t type, int flag, void *val, int nelems, int *err) +{ + int ret; + topo_hdl_t *thp = node->tn_hdl; + nvlist_t *nvl; + topo_propval_t *pv; + + if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) { + *err = ETOPO_PROP_NVL; + return (-1); + } + + ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname); + ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type); switch (type) { case TOPO_TYPE_INT32: - ret = nvlist_add_int32(pv->tp_val, TOPO_PROP_VAL_VAL, + ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, *(int32_t *)val); break; case TOPO_TYPE_UINT32: - ret = nvlist_add_uint32(pv->tp_val, TOPO_PROP_VAL_VAL, + ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, *(uint32_t *)val); break; case TOPO_TYPE_INT64: - ret = nvlist_add_int64(pv->tp_val, TOPO_PROP_VAL_VAL, + ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, *(int64_t *)val); break; case TOPO_TYPE_UINT64: - ret = nvlist_add_uint64(pv->tp_val, TOPO_PROP_VAL_VAL, + ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, *(uint64_t *)val); break; case TOPO_TYPE_STRING: - ret = nvlist_add_string(pv->tp_val, TOPO_PROP_VAL_VAL, + ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, (char *)val); break; case TOPO_TYPE_FMRI: - ret = nvlist_add_nvlist(pv->tp_val, TOPO_PROP_VAL_VAL, + ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, (nvlist_t *)val); break; case TOPO_TYPE_INT32_ARRAY: - ret = nvlist_add_int32_array(pv->tp_val, + ret |= nvlist_add_int32_array(nvl, TOPO_PROP_VAL_VAL, (int32_t *)val, nelems); break; case TOPO_TYPE_UINT32_ARRAY: - ret = nvlist_add_uint32_array(pv->tp_val, + ret |= nvlist_add_uint32_array(nvl, TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems); break; case TOPO_TYPE_INT64_ARRAY: - ret = nvlist_add_int64_array(pv->tp_val, + ret |= nvlist_add_int64_array(nvl, TOPO_PROP_VAL_VAL, (int64_t *)val, nelems); break; case TOPO_TYPE_UINT64_ARRAY: - ret = nvlist_add_uint64_array(pv->tp_val, + ret |= nvlist_add_uint64_array(nvl, TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems); break; case TOPO_TYPE_STRING_ARRAY: - ret = nvlist_add_string_array(pv->tp_val, + ret |= nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, (char **)val, nelems); break; case TOPO_TYPE_FMRI_ARRAY: - ret = nvlist_add_nvlist_array(pv->tp_val, + ret |= nvlist_add_nvlist_array(nvl, TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems); break; default: - return (set_seterror(node, pvl, err, ETOPO_PROP_TYPE)); + *err = ETOPO_PROP_TYPE; + return (-1); } if (ret != 0) { - if (ret == ENOMEM) - return (set_seterror(node, pvl, err, ETOPO_NOMEM)); - else - return (set_seterror(node, pvl, err, ETOPO_PROP_NVL)); + nvlist_free(nvl); + if (ret == ENOMEM) { + *err = ETOPO_PROP_NOMEM; + return (-1); + } else { + *err = ETOPO_PROP_NVL; + return (-1); + } } - if (new_prop > 0) - topo_list_append(&pg->tpg_pvals, pvl); + topo_node_lock(node); + if ((pv = prop_create(node, pgname, pname, type, flag, err)) == NULL) { + nvlist_free(nvl); + return (-1); /* unlocked and err set */ + } + + pv->tp_val = nvl; topo_node_unlock(node); - return (0); + return (ret); } int @@ -835,6 +722,218 @@ (void *)fmri, nelems, err)); } +/* + * topo_prop_setprop() is a private project function for fmtopo + */ +int +topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop, + int flag, nvlist_t *pargs, int *err) +{ + int ret; + topo_hdl_t *thp = node->tn_hdl; + topo_propval_t *pv; + nvlist_t *nvl, *args; + char *name; + topo_type_t type; + + if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) { + *err = ETOPO_PROP_NAME; + return (-1); + } + if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type) + != 0) { + *err = ETOPO_PROP_TYPE; + return (-1); + } + + topo_node_lock(node); + if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL) + return (-1); /* unlocked and err set */ + + /* + * Set by method or set to new prop value. If we fail, leave + * property in list with old value. + */ + if (pv->tp_method != NULL) { + topo_propmethod_t *pm = pv->tp_method; + + if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) { + topo_node_unlock(node); + *err = ETOPO_PROP_NOMEM; + return (-1); + } + ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args); + if (pargs != NULL) + ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs); + + if (ret != 0) { + topo_node_unlock(node); + nvlist_free(args); + *err = ETOPO_PROP_NVL; + return (-1); + } + + ret = topo_method_call(node, pm->tpm_name, pm->tpm_version, + args, &nvl, err); + nvlist_free(args); + } else { + if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0) + *err = ETOPO_PROP_NOMEM; + } + + if (ret != 0) { + topo_node_unlock(node); + return (-1); + } + + pv->tp_val = nvl; + topo_node_unlock(node); + return (0); +} + +static int +register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l, + int err) +{ + topo_hdl_t *thp = node->tn_hdl; + + if (pm != NULL) { + if (pm->tpm_name != NULL) + topo_hdl_strfree(thp, pm->tpm_name); + if (pm->tpm_args != NULL) + nvlist_free(pm->tpm_args); + topo_hdl_free(thp, pm, sizeof (topo_propmethod_t)); + } + + *errp = err; + + if (l != 0) + topo_node_unlock(node); + + return (-1); +} + +int +prop_method_register(tnode_t *node, const char *pgname, const char *pname, + topo_type_t ptype, const char *mname, topo_version_t version, + const nvlist_t *args, int *err) +{ + topo_hdl_t *thp = node->tn_hdl; + topo_propmethod_t *pm = NULL; + topo_propval_t *pv = NULL; + + if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL) + return (register_methoderror(node, pm, err, 1, + ETOPO_PROP_NOMEM)); + + if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL) + return (register_methoderror(node, pm, err, 1, + ETOPO_PROP_NOMEM)); + + pm->tpm_version = version; + + if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0) + return (register_methoderror(node, pm, err, 1, + ETOPO_PROP_NOMEM)); + + if ((pv = prop_create(node, pgname, pname, ptype, TOPO_PROP_MUTABLE, + err)) == NULL) { + /* node unlocked */ + return (register_methoderror(node, pm, err, 0, *err)); + } + + if (pv->tp_method != NULL) { + topo_node_unlock(node); + return (register_methoderror(node, pm, err, 1, + ETOPO_METHOD_DEFD)); + } + + pv->tp_val = NULL; + pv->tp_method = pm; + + topo_node_unlock(node); + + return (0); +} + +int +topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname, + topo_type_t ptype, const char *mname, const nvlist_t *args, int *err) +{ + topo_imethod_t *mp; + + topo_node_lock(node); + + if ((mp = topo_method_lookup(node, mname)) == NULL) + return (register_methoderror(node, NULL, err, 1, + ETOPO_METHOD_NOTSUP)); + + return (prop_method_register(node, pgname, pname, ptype, mname, + mp->tim_version, args, err)); /* err set and node unlocked */ +} + +int +topo_prop_method_version_register(tnode_t *node, const char *pgname, + const char *pname, topo_type_t ptype, const char *mname, + topo_version_t version, const nvlist_t *args, int *err) +{ + topo_imethod_t *mp; + + topo_node_lock(node); + + if ((mp = topo_method_lookup(node, mname)) == NULL) + return (register_methoderror(node, NULL, err, 1, + ETOPO_METHOD_NOTSUP)); + + if (version < mp->tim_version) + return (register_methoderror(node, NULL, err, 1, + ETOPO_METHOD_VEROLD)); + if (version > mp->tim_version) + return (register_methoderror(node, NULL, err, 1, + ETOPO_METHOD_VERNEW)); + + return (prop_method_register(node, pgname, pname, ptype, mname, + version, args, err)); /* err set and node unlocked */ +} + +void +topo_prop_method_unregister(tnode_t *node, const char *pgname, + const char *pname) +{ + topo_propval_t *pv; + topo_pgroup_t *pg; + topo_proplist_t *pvl; + topo_hdl_t *thp = node->tn_hdl; + + topo_node_lock(node); + + for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; + pg = topo_list_next(pg)) { + if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) { + break; + } + } + + if (pg == NULL) { + topo_node_unlock(node); + return; + } + + for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL; + pvl = topo_list_next(pvl)) { + pv = pvl->tp_pval; + if (strcmp(pv->tp_name, pname) == 0) { + topo_list_delete(&pg->tpg_pvals, pvl); + assert(pv->tp_refs == 1); + topo_prop_rele(pv); + topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); + break; + } + } + + topo_node_unlock(node); +} + static int inherit_seterror(tnode_t *node, int *errp, int err) { @@ -860,10 +959,7 @@ /* * Check for an existing property group and prop val */ - if ((pg = pgroup_get(pnode, pgname)) == NULL) - return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); - - if ((pv = propval_get(pg, name)) == NULL) + if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL) return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); /* @@ -1068,10 +1164,32 @@ } topo_node_unlock(node); } + +static void +propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv) +{ + topo_propmethod_t *pm; + + pm = pv->tp_method; + if (pm != NULL) { + if (pm->tpm_name != NULL) + topo_hdl_strfree(thp, pm->tpm_name); + if (pm->tpm_args != NULL) + nvlist_free(pm->tpm_args); + topo_hdl_free(thp, pm, sizeof (topo_propmethod_t)); + pv->tp_method = NULL; + } +} + static void topo_propval_destroy(topo_propval_t *pv) { - topo_hdl_t *thp = pv->tp_hdl; + topo_hdl_t *thp; + + if (pv == NULL) + return; + + thp = pv->tp_hdl; if (pv->tp_name != NULL) topo_hdl_strfree(thp, pv->tp_name); @@ -1079,6 +1197,8 @@ if (pv->tp_val != NULL) nvlist_free(pv->tp_val); + propmethod_destroy(thp, pv); + topo_hdl_free(thp, pv, sizeof (topo_propval_t)); } @@ -1098,3 +1218,199 @@ if (pv->tp_refs == 0) topo_propval_destroy(pv); } + +/* + * topo_prop_getprop() and topo_prop_getprops() are private project functions + * for fmtopo + */ +int +topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname, + nvlist_t *args, nvlist_t **prop, int *err) +{ + topo_hdl_t *thp = node->tn_hdl; + topo_propval_t *pv; + + topo_node_lock(node); + if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) { + topo_node_unlock(node); + (void) get_properror(node, err, *err); + return (-1); + } + + if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) { + topo_node_unlock(node); + (void) get_properror(node, err, ETOPO_NOMEM); + return (-1); + } + topo_node_unlock(node); + + return (0); +} + +static int +prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err) +{ + if (pv->tp_method != NULL) + if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0) + return (-1); + + if (pv->tp_val == NULL) { + *err = ETOPO_PROP_NOENT; + return (-1); + } + + if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) { + *err = ETOPO_PROP_NOMEM; + return (-1); + } + + return (0); +} + +static int +get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err) +{ + topo_node_unlock(node); + + if (nvl != NULL) + nvlist_free(nvl); + + *errp = err; + + return (-1); +} + +int +topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp, + int *err) +{ + int ret; + topo_hdl_t *thp = node->tn_hdl; + nvlist_t *nvl, *pvnvl; + topo_pgroup_t *pg; + topo_propval_t *pv; + topo_proplist_t *pvl; + + if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { + *err = ETOPO_NOMEM; + return (-1); + } + + topo_node_lock(node); + for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; + pg = topo_list_next(pg)) { + + if (strcmp(pgname, pg->tpg_info->tpi_name) != 0) + continue; + + if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME, + pg->tpg_info->tpi_name) != 0 || + nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB, + topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 || + nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB, + topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 || + nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION, + pg->tpg_info->tpi_version) != 0) + return (get_pgrp_seterror(node, nvl, err, + ETOPO_PROP_NVL)); + + for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; + pvl = topo_list_next(pvl)) { + + pv = pvl->tp_pval; + if (prop_val_add(node, &pvnvl, pv, err) < 0) { + return (get_pgrp_seterror(node, nvl, err, + *err)); + } + if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL, + pvnvl)) != 0) { + nvlist_free(pvnvl); + return (get_pgrp_seterror(node, nvl, err, ret)); + } + + nvlist_free(pvnvl); + } + topo_node_unlock(node); + *pgrp = nvl; + return (0); + } + + topo_node_unlock(node); + *err = ETOPO_PROP_NOENT; + return (-1); +} + +static nvlist_t * +get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err) +{ + topo_node_unlock(node); + + if (nvl != NULL) + nvlist_free(nvl); + + *errp = err; + + return (NULL); +} + +nvlist_t * +topo_prop_getprops(tnode_t *node, int *err) +{ + int ret; + topo_hdl_t *thp = node->tn_hdl; + nvlist_t *nvl, *pgnvl, *pvnvl; + topo_pgroup_t *pg; + topo_propval_t *pv; + topo_proplist_t *pvl; + + topo_node_lock(node); + if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { + return (get_all_seterror(node, NULL, err, ETOPO_NOMEM)); + } + + for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; + pg = topo_list_next(pg)) { + if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0) + return (get_all_seterror(node, nvl, err, ETOPO_NOMEM)); + + if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME, + pg->tpg_info->tpi_name) != 0 || + nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB, + topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 || + nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB, + topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 || + nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION, + pg->tpg_info->tpi_version) != 0) + return (get_all_seterror(node, nvl, err, + ETOPO_PROP_NVL)); + + for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; + pvl = topo_list_next(pvl)) { + + pv = pvl->tp_pval; + if (prop_val_add(node, &pvnvl, pv, err) < 0) { + nvlist_free(pgnvl); + return (get_all_seterror(node, nvl, err, *err)); + } + if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL, + pvnvl)) != 0) { + nvlist_free(pgnvl); + nvlist_free(pvnvl); + return (get_all_seterror(node, nvl, err, ret)); + } + + nvlist_free(pvnvl); + } + if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl)) + != 0) { + nvlist_free(pgnvl); + return (get_all_seterror(node, nvl, err, ret)); + } + + nvlist_free(pgnvl); + } + + topo_node_unlock(node); + + return (nvl); +}
--- a/usr/src/lib/fm/topo/libtopo/common/topo_prop.h Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_prop.h Mon Apr 23 15:34:38 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -49,6 +49,12 @@ topo_list_t tpg_pvals; /* property values */ } topo_pgroup_t; +typedef struct topo_propmethod { + char *tpm_name; /* property method name */ + topo_version_t tpm_version; /* method version */ + nvlist_t *tpm_args; /* in args for method */ +} topo_propmethod_t; + typedef struct topo_propval { char *tp_name; /* prop name */ topo_type_t tp_type; /* prop type */ @@ -57,6 +63,7 @@ topo_hdl_t *tp_hdl; /* handle pointer for allocations */ void (*tp_free)(struct topo_propval *); /* prop value destructor */ nvlist_t *tp_val; + topo_propmethod_t *tp_method; /* Method for accessing dynamic prop */ } topo_propval_t; typedef struct topo_proplist { @@ -67,6 +74,8 @@ extern void topo_prop_hold(topo_propval_t *); extern void topo_prop_rele(topo_propval_t *); extern void topo_pgroup_destroy_all(tnode_t *); +extern nvlist_t *topo_prop_get(tnode_t *, const char *, const char *, + topo_type_t, nvlist_t *, int *err); #ifdef __cplusplus }
--- a/usr/src/lib/fm/topo/libtopo/common/topo_protocol.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_protocol.c Mon Apr 23 15:34:38 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,91 +33,52 @@ #include <topo_alloc.h> #include <topo_error.h> #include <topo_method.h> +#include <topo_prop.h> #include <topo_protocol.h> #include <topo_subr.h> #include <libtopo.h> -static int -topo_compute(tnode_t *node, nvlist_t *stub, const char *method, - topo_version_t version, nvlist_t *rsrc, nvlist_t **asru, int *err) +int +topo_node_asru(tnode_t *node, nvlist_t **asru, nvlist_t *priv, int *err) { - int rc; - char *scheme; - topo_hdl_t *thp = node->tn_hdl; - tnode_t *rnode; + nvlist_t *prop, *ap; - /* - * First try the originating enumerator for - * a compute method. If none is supported, try the - * node's scheme-specific enumerator. - */ - if (topo_method_invoke(node, method, version, rsrc, asru, err) == 0) - return (0); - - if (*err != ETOPO_METHOD_NOTSUP) + if (topo_prop_getprop(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_ASRU, priv, &prop, err) < 0) return (-1); - if ((rc = nvlist_lookup_string(stub, FM_FMRI_SCHEME, &scheme)) != 0) { - if (rc == ENOENT) { - *err = ETOPO_FMRI_MALFORM; - } else { - *err = ETOPO_FMRI_NVL; - } + if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0 || + topo_hdl_nvdup(node->tn_hdl, ap, asru) < 0) { + *err = ETOPO_PROP_NVL; + nvlist_free(prop); return (-1); } - if ((rnode = topo_hdl_root(thp, scheme)) == NULL) { - *err = ETOPO_METHOD_NOTSUP; - return (-1); - } - - if (topo_method_invoke(rnode, method, version, rsrc, asru, err) != 0) - return (-1); + nvlist_free(prop); return (0); } int -topo_node_asru(tnode_t *node, nvlist_t **asru, nvlist_t *priv, int *err) +topo_node_fru(tnode_t *node, nvlist_t **fru, nvlist_t *priv, int *err) { - int rc; - nvlist_t *ap; + nvlist_t *prop, *fp; - if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, &ap, - err) != 0) + if (topo_prop_getprop(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, + priv, &prop, err) < 0) return (-1); - if (node->tn_fflags & TOPO_ASRU_COMPUTE) { - rc = topo_compute(node, ap, TOPO_METH_ASRU_COMPUTE, - TOPO_METH_ASRU_COMPUTE_VERSION, priv, asru, err); - nvlist_free(ap); - return (rc); - } else { - *asru = ap; - return (0); + if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0 || + topo_hdl_nvdup(node->tn_hdl, fp, fru) < 0) { + *err = ETOPO_PROP_NVL; + nvlist_free(prop); + return (-1); } -} -int -topo_node_fru(tnode_t *node, nvlist_t **fru, nvlist_t *priv, int *err) -{ - int rc; - nvlist_t *fp; - - if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, &fp, - err) != 0) - return (-1); + nvlist_free(prop); - if (node->tn_fflags & TOPO_FRU_COMPUTE) { - rc = topo_compute(node, fp, TOPO_METH_FRU_COMPUTE, - TOPO_METH_FRU_COMPUTE_VERSION, priv, fru, err); - nvlist_free(fp); - return (rc); - } else { - *fru = fp; - return (0); - } + return (0); } int @@ -139,24 +100,24 @@ int topo_node_asru_set(tnode_t *node, nvlist_t *asru, int flag, int *err) { - /* - * Inherit ASRU property from our parent if not specified + * Inherit ASRU property from our parent if asru not specified */ if (asru == NULL) { if (topo_prop_inherit(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, err) < 0) { return (-1); } + + return (0); + } + + if (flag & TOPO_ASRU_COMPUTE) { + if (topo_prop_method_register(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_ASRU, TOPO_TYPE_FMRI, TOPO_METH_ASRU_COMPUTE, + asru, err) < 0) + return (-1); } else { - /* - * ASRU must be computed on the fly. asru will - * contain the scheme module to call for the - * computation - */ - if (flag & TOPO_ASRU_COMPUTE) - node->tn_fflags |= TOPO_ASRU_COMPUTE; - if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, TOPO_PROP_IMMUTABLE, asru, err) < 0) return (-1); @@ -177,18 +138,20 @@ err) < 0) { return (-1); } + } + + if (flag & TOPO_FRU_COMPUTE) { + if (topo_prop_method_register(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_FRU, TOPO_TYPE_FMRI, TOPO_METH_FRU_COMPUTE, + fru, err) < 0) + return (-1); } else { - /* - * FRU must be computed on the fly - */ - if (flag & TOPO_FRU_COMPUTE) - node->tn_fflags |= TOPO_FRU_COMPUTE; - if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, TOPO_PROP_IMMUTABLE, fru, err) < 0) return (-1); } + return (0); }
--- a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c Mon Apr 23 15:34:38 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -54,14 +54,13 @@ * which our current walk falls. The callback function is passed in during * calls to topo_walk_init() and used throughout the walk_step of the * scheme tree. At any time, the callback may terminate the walk by returning - * TOPO_WALK_TERMINATE or TOPO_WALK_ERR. TOPO_WALK_NEXT will continue the - * walk. + * TOPO_WALK_TERMINATE or TOPO_WALK_ERR. TOPO_WALK_NEXT will continue the walk. * - * Walks through the tree may be breadth first or depth first by + * The type of walk through the tree may be breadth first or depth first by * respectively passing in TOPO_WALK_SIBLING or TOPO_WALK_CHILD to - * the topo_walk_step() function. Topology nodes associated with an - * outstanding walk are held in place and will not be deallocated until - * the walk through that node completes. + * the topo_walk_step() function. Topology nodes + * associated with an outstanding walk are held in place and will not be + * deallocated until the walk through that node completes. * * Once the walk has terminated, the walking process should call * topo_walk_fini() to clean-up resources created in topo_walk_init() @@ -163,10 +162,8 @@ (void) pthread_mutex_init(&thp->th_lock, NULL); - if ((tap = topo_zalloc(sizeof (topo_alloc_t), 0)) == NULL) { - topo_close(thp); + if ((tap = topo_zalloc(sizeof (topo_alloc_t), 0)) == NULL) return (set_open_errno(thp, errp, ETOPO_NOMEM)); - } /* * Install default allocators @@ -230,10 +227,8 @@ thp->th_product = topo_hdl_strdup(thp, thp->th_platform); } - if (thp->th_rootdir == NULL) { - topo_close(thp); + if (thp->th_rootdir == NULL) return (set_open_errno(thp, errp, ETOPO_NOMEM)); - } dbflags = getenv("TOPO_DEBUG"); dbout = getenv("TOPO_DEBUG_OUT"); @@ -445,7 +440,6 @@ topo_walk_init(topo_hdl_t *thp, const char *scheme, topo_walk_cb_t cb_f, void *pdata, int *errp) { - tnode_t *child; ttree_t *tp; topo_walk_t *wp; @@ -459,31 +453,9 @@ */ assert(tp->tt_root != NULL); - topo_node_hold(tp->tt_root); - - /* - * Nothing to walk - */ - if ((child = topo_child_first(tp->tt_root)) == NULL) { - *errp = ETOPO_WALK_EMPTY; - topo_node_rele(tp->tt_root); + if ((wp = topo_node_walk_init(thp, NULL, tp->tt_root, + cb_f, pdata, errp)) == NULL) /* errp set */ return (NULL); - } - - if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) - == NULL) { - *errp = ETOPO_NOMEM; - topo_node_rele(tp->tt_root); - return (NULL); - } - - topo_node_hold(child); - - wp->tw_root = tp->tt_root; - wp->tw_node = child; - wp->tw_cb = cb_f; - wp->tw_pdata = pdata; - wp->tw_thp = thp; return (wp); } @@ -501,12 +473,16 @@ nnp = topo_child_first(cnp); - if (nnp == NULL) + if (nnp == NULL) { + topo_dprintf(wp->tw_thp, TOPO_DBG_WALK, + "step_child: TOPO_WALK_TERMINATE for %s=%d\n", + cnp->tn_name, cnp->tn_instance); return (TOPO_WALK_TERMINATE); + } topo_dprintf(wp->tw_thp, TOPO_DBG_WALK, - "walk through child node %s=%d\n", - nnp->tn_name, nnp->tn_instance); + "step_child: walk through node %s=%d to %s=%d\n", + cnp->tn_name, cnp->tn_instance, nnp->tn_name, nnp->tn_instance); topo_node_hold(nnp); /* released on return from walk_step */ wp->tw_node = nnp; @@ -526,12 +502,16 @@ nnp = topo_child_next(cnp->tn_parent, cnp); - if (nnp == NULL) + if (nnp == NULL) { + topo_dprintf(wp->tw_thp, TOPO_DBG_WALK, + "step_sibling: TOPO_WALK_TERMINATE for %s=%d\n", + cnp->tn_name, cnp->tn_instance); return (TOPO_WALK_TERMINATE); + } topo_dprintf(wp->tw_thp, TOPO_DBG_WALK, - "walk through sibling node %s=%d\n", - nnp->tn_name, nnp->tn_instance); + "step_sibling: through sibling node %s=%d to %s=%d\n", + cnp->tn_name, cnp->tn_instance, nnp->tn_name, nnp->tn_instance); topo_node_hold(nnp); /* released on return from walk_step */ wp->tw_node = nnp; @@ -544,6 +524,29 @@ } int +topo_walk_byid(topo_walk_t *wp, const char *name, topo_instance_t inst) +{ + int status; + tnode_t *nnp, *cnp; + + cnp = wp->tw_node; + nnp = topo_node_lookup(cnp, name, inst); + if (nnp == NULL) + return (TOPO_WALK_TERMINATE); + + topo_node_hold(nnp); + wp->tw_node = nnp; + if (wp->tw_mod != NULL) + status = wp->tw_cb(wp->tw_mod, nnp, wp->tw_pdata); + else + status = wp->tw_cb(wp->tw_thp, nnp, wp->tw_pdata); + topo_node_rele(nnp); + wp->tw_node = cnp; + + return (status); +} + +int topo_walk_step(topo_walk_t *wp, int flag) { int status; @@ -555,7 +558,7 @@ } /* - * End of the line + * No more nodes to walk */ if (cnp == NULL) { topo_dprintf(wp->tw_thp, TOPO_DBG_WALK, @@ -564,30 +567,32 @@ return (TOPO_WALK_TERMINATE); } - topo_dprintf(wp->tw_thp, TOPO_DBG_WALK, - "%s walk_step through node %s=%d\n", - (flag == TOPO_WALK_CHILD ? "TOPO_WALK_CHILD" : "TOPO_WALK_SIBLING"), - cnp->tn_name, cnp->tn_instance); - if ((status = wp->tw_cb(wp->tw_thp, cnp, wp->tw_pdata)) - != TOPO_WALK_NEXT) { + if (wp->tw_mod != NULL) + status = wp->tw_cb(wp->tw_mod, cnp, wp->tw_pdata); + else + status = wp->tw_cb(wp->tw_thp, cnp, wp->tw_pdata); + + /* + * Walker callback says we're done + */ + if (status != TOPO_WALK_NEXT) { topo_node_rele(cnp); return (status); } - if (flag == TOPO_WALK_CHILD) - status = step_child(cnp, wp, 0); - else - status = step_sibling(cnp, wp, 0); + flag == TOPO_WALK_CHILD ? (status = step_child(cnp, wp, 0)) : + (status = step_sibling(cnp, wp, 0)); /* - * End of the walk, try next child or sibling + * No more nodes in this hash, skip to next node hash by stepping + * to next sibling (depth-first walk) or next child (breadth-first + * walk). */ if (status == TOPO_WALK_TERMINATE) { - if (flag == TOPO_WALK_CHILD) - status = step_sibling(cnp, wp, 0); - else - status = step_child(cnp, wp, 0); + + flag == TOPO_WALK_CHILD ? (status = step_sibling(cnp, wp, 0)) : + (status = step_child(cnp, wp, 0)); } topo_node_rele(cnp); /* done with current node */
--- a/usr/src/lib/fm/topo/libtopo/common/topo_subr.h Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_subr.h Mon Apr 23 15:34:38 2007 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -88,6 +88,8 @@ extern void topo_fmristr_build(ssize_t *, char *, size_t, char *, char *, char *); +extern int topo_walk_byid(topo_walk_t *wp, const char *name, topo_instance_t); + #ifdef __cplusplus } #endif
--- a/usr/src/lib/fm/topo/libtopo/common/topo_tree.h Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_tree.h Mon Apr 23 15:34:38 2007 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,6 +33,7 @@ #include <topo_list.h> #include <topo_prop.h> +#include <topo_method.h> #ifdef __cplusplus extern "C" { @@ -54,19 +55,6 @@ topo_range_t th_range; /* instance ranges for nodes */ } topo_nodehash_t; -typedef struct topo_imethod { - topo_list_t tim_list; /* next/prev pointers */ - pthread_mutex_t tim_lock; /* method entry lock */ - pthread_cond_t tim_cv; /* method entry cv */ - uint_t tim_busy; /* method entry busy indicator */ - char *tim_name; /* Method name */ - topo_version_t tim_version; /* Method version */ - topo_stability_t tim_stability; /* SMI stability of method */ - char *tim_desc; /* Method description */ - topo_method_f *tim_func; /* Method function */ - struct topo_mod *tim_mod; /* Ptr to controlling module */ -} topo_imethod_t; - struct topo_node { pthread_mutex_t tn_lock; /* lock protecting members */ char *tn_name; /* Node name */ @@ -101,8 +89,9 @@ struct topo_hdl *tw_thp; /* Topo handle pointer */ struct topo_node *tw_root; /* Root node of current walk */ struct topo_node *tw_node; /* Current walker node */ - topo_walk_cb_t tw_cb; /* Walker callback function */ + int (*tw_cb)(); /* Walker callback function */ void *tw_pdata; /* Private callback data */ + topo_mod_t *tw_mod; /* module if walking from plugin */ }; typedef struct topo_alloc { @@ -148,6 +137,8 @@ extern int topo_node_hash(topo_nodehash_t *, topo_instance_t); extern int topo_walk_bottomup(topo_walk_t *, int); +extern topo_walk_t *topo_node_walk_init(topo_hdl_t *, topo_mod_t *, tnode_t *, + topo_walk_cb_t, void *, int *); #ifdef __cplusplus }
--- a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c Mon Apr 23 15:34:38 2007 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -838,7 +838,7 @@ */ xmlNodePtr cn; tnode_t *ct; - int e; + int e, ccnt = 0; topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "process %s range beneath %s\n", rd->rd_name, topo_node_name(rd->rd_pn)); @@ -889,7 +889,16 @@ if (pad_process(mp, rd->rd_finfo, rn, ct, &rd->rd_pad) < 0) return (-1); ct = topo_child_next(rd->rd_pn, ct); + ccnt++; } + + if (ccnt == 0) { + topo_node_range_destroy(rd->rd_pn, rd->rd_name); + topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "no nodes processed for " + "range %s\n", rd->rd_name); + return (-1); + } + topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "end range process %s\n", rd->rd_name); return (0); @@ -922,7 +931,10 @@ } if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) { tf_rdata_free(mp, rr); - return (NULL); + /* + * Range processing error, continue walk + */ + continue; } if (pr == NULL) { rr = pr = rdp; @@ -1008,12 +1020,14 @@ if ((dtd = xmlGetIntSubset(document)) == NULL) { topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document has no DTD.\n"); + xmlFreeDoc(document); return (NULL); } if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) { topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document DTD unknown; bad topology file\n"); + xmlFreeDoc(document); return (NULL); } @@ -1056,6 +1070,8 @@ topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "Could not parse DTD \"%s\".\n", dtdpath); + xmlFree(scheme); + xmlFreeDoc(document); return (NULL); } @@ -1066,6 +1082,8 @@ } if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {; + xmlFree(scheme); + xmlFreeDoc(document); topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "couldn't handle XInclude statements in document\n"); return (NULL); @@ -1074,7 +1092,7 @@ if (validate) { if ((vcp = xmlNewValidCtxt()) == NULL) { xmlFree(scheme); - scheme = NULL; + xmlFreeDoc(document); return (NULL); } vcp->warning = xmlParserValidityWarning; @@ -1089,8 +1107,11 @@ "Document is not valid.\n"); } - if ((r = tf_info_new(tmp, document, scheme)) == NULL) + if ((r = tf_info_new(tmp, document, scheme)) == NULL) { + xmlFree(scheme); + xmlFreeDoc(document); return (NULL); + } xmlFree(scheme); scheme = NULL;
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c Mon Apr 23 12:50:31 2007 -0700 +++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c Mon Apr 23 15:34:38 2007 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -578,34 +578,20 @@ * asru-physaddr or asru-offset then these are includes in the "mem" scheme * asru as additional membersl physaddr and offset */ -/*ARGSUSED*/ static int -mem_asru_compute(topo_mod_t *mod, tnode_t *node, topo_version_t version, - nvlist_t *in, nvlist_t **out) +mem_asru_create(topo_mod_t *mod, nvlist_t *fmri, nvlist_t **asru) { int incl_pa = 0, incl_offset = 0; - nvlist_t *hcsp, *asru; + nvlist_t *hcsp, *ap; + char *unum, *scheme; uint64_t pa, offset; - char *scheme, *unum; int err; - if (strcmp(topo_node_name(node), RANK_NODE_NAME) != 0 && - strcmp(topo_node_name(node), DIMM_NODE_NAME) != 0) + if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0 || + strcmp(scheme, FM_FMRI_SCHEME_HC) != 0) return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); - if (in == NULL) { - if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, - TOPO_PROP_ASRU, out, &err) == 0) - return (0); - else - return (topo_mod_seterrno(mod, err)); - } else { - if (nvlist_lookup_string(in, FM_FMRI_SCHEME, &scheme) != 0 || - strcmp(scheme, FM_FMRI_SCHEME_HC) != 0) - return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); - } - - if (nvlist_lookup_nvlist(in, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) { + if (nvlist_lookup_nvlist(fmri, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) { if (nvlist_lookup_uint64(hcsp, "asru-"FM_FMRI_MEM_PHYSADDR, &pa) == 0) incl_pa = 1; @@ -615,28 +601,75 @@ incl_offset = 1; } - /* use 'in' to obtain resource path; could use node resource */ - if (topo_mod_nvl2str(mod, in, &unum) < 0) - return (topo_mod_seterrno(mod, err)); + /* use 'fmri' to obtain resource path; could use node resource */ + if (topo_mod_nvl2str(mod, fmri, &unum) < 0) + return (-1); /* mod errno set */ - if ((asru = mem_fmri_create(mod)) == NULL) { + if ((ap = mem_fmri_create(mod)) == NULL) { topo_mod_strfree(mod, unum); return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); } - err = nvlist_add_string(asru, FM_FMRI_MEM_UNUM, unum); + err = nvlist_add_string(ap, FM_FMRI_MEM_UNUM, unum); if (incl_pa) - err |= nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR, pa); + err |= nvlist_add_uint64(ap, FM_FMRI_MEM_PHYSADDR, pa); if (incl_offset) - err |= nvlist_add_uint64(asru, FM_FMRI_MEM_OFFSET, offset); + err |= nvlist_add_uint64(ap, FM_FMRI_MEM_OFFSET, offset); topo_mod_strfree(mod, unum); if (err != 0) { - nvlist_free(asru); + nvlist_free(ap); return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); } - *out = asru; + *asru = ap; + + return (0); +} + +/*ARGSUSED*/ +static int +mem_asru_compute(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + nvlist_t *asru; + nvlist_t *args, *pargs; + int err; + + if (strcmp(topo_node_name(node), RANK_NODE_NAME) != 0 && + strcmp(topo_node_name(node), DIMM_NODE_NAME) != 0) + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + + if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0) + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + + if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs)) != 0) { + if (err == ENOENT) { + if (topo_mod_nvdup(mod, args, &asru) < 0) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + } else { + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + } + } else if (mem_asru_create(mod, pargs, &asru) != 0) { + return (-1); /* mod errno already set */ + } + + if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) { + nvlist_free(asru); + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + } + + err = nvlist_add_string(*out, TOPO_PROP_VAL_NAME, TOPO_PROP_ASRU); + err |= nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_FMRI); + err |= nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, asru); + if (err != 0) { + nvlist_free(asru); + nvlist_free(*out); + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } + + nvlist_free(asru); + return (0); } @@ -705,13 +738,13 @@ * the asru is just that page. Hence the dual preconstructed * and computed ASRU. */ - (void) topo_node_asru_set(ranknode, cs_fmri[csnumarr[i]], - TOPO_ASRU_COMPUTE, &err); - if (topo_method_register(mod, ranknode, rank_methods) < 0) whinge(mod, &nerr, "rank_create: " "topo_method_register failed"); + (void) topo_node_asru_set(ranknode, cs_fmri[csnumarr[i]], + TOPO_ASRU_COMPUTE, &err); + (void) topo_pgroup_create(ranknode, &rank_pgroup, &err); (void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "size", @@ -774,12 +807,10 @@ } /* - * The asru is static but we prefer to publish it in the - * "mem" scheme so call the compute method directly to - * perform the conversion. + * Use the mem computation method directly to publish the asru + * in the "mem" scheme. */ - if (mem_asru_compute(mod, dimmnode, - TOPO_METH_ASRU_COMPUTE_VERSION, fmri, &asru) == 0) { + if (mem_asru_create(mod, fmri, &asru) == 0) { (void) topo_node_asru_set(dimmnode, asru, 0, &err); nvlist_free(asru); } else { @@ -820,7 +851,7 @@ void *buf = NULL; uint8_t ver; - nvlist_t *nvl; + nvlist_t *nvl = NULL; char path[64]; int fd, err; @@ -861,6 +892,7 @@ err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); topo_mod_free(mod, buf, mcs.mcs_size); + if (nvlist_lookup_uint8(nvl, MC_NVLIST_VERSTR, &ver) != 0) { whinge(mod, NULL, "mc nvlist is not versioned\n"); nvlist_free(nvl);