1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <ctype.h> 28 #include <string.h> 29 #include <limits.h> 30 #include <fm/topo_mod.h> 31 #include <fm/fmd_fmri.h> 32 #include <sys/fm/protocol.h> 33 #include <topo_alloc.h> 34 #include <topo_error.h> 35 #include <topo_hc.h> 36 #include <topo_method.h> 37 #include <topo_subr.h> 38 #include <topo_string.h> 39 40 /* 41 * Topology node properties and method operations may be accessed by FMRI. 42 * The FMRI used to perform property look-ups and method operations is 43 * the FMRI contained in the matching topology node's protocol property 44 * grouping for the resource property. The full range of fmd(1M) 45 * scheme plugin operations are supported as long as a backend method is 46 * supplied by a scheme-specific enumerator or the enumerator module that 47 * created the matching topology node. Support for fmd scheme operations 48 * include: 49 * 50 * - expand 51 * - present 52 * - replaced 53 * - contains 54 * - unusable 55 * - service_state 56 * - nvl2str 57 * - retire 58 * - unretire 59 * 60 * In addition, the following operations are supported per-FMRI: 61 * 62 * - str2nvl: convert string-based FMRI to nvlist 63 * - compare: compare two FMRIs 64 * - asru: lookup associated ASRU property by FMRI 65 * - fru: lookup associated FRU by FMRI 66 * - create: an FMRI nvlist by scheme type 67 * - propery lookup 68 * 69 * These routines may only be called by consumers of a topology snapshot. 70 * They may not be called by libtopo enumerator or method modules. 71 */ 72 73 /*ARGSUSED*/ 74 static int 75 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 76 { 77 if (nvlp != NULL) 78 nvlist_free(nvlp); 79 80 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 81 topo_strerror(err)); 82 83 *errp = err; 84 return (-1); 85 } 86 87 /*ARGSUSED*/ 88 static nvlist_t * 89 set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 90 { 91 if (nvlp != NULL) 92 nvlist_free(nvlp); 93 94 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 95 topo_strerror(err)); 96 97 *errp = err; 98 return (NULL); 99 } 100 101 int 102 topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err) 103 { 104 char *scheme, *str; 105 nvlist_t *out = NULL; 106 tnode_t *rnode; 107 108 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 109 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 110 TOPO_METH_NVL2STR, out)); 111 112 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 113 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 114 TOPO_METH_NVL2STR, out)); 115 116 if (topo_method_invoke(rnode, TOPO_METH_NVL2STR, 117 TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0) 118 return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out)); 119 120 if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0) 121 return (set_error(thp, ETOPO_METHOD_INVAL, err, 122 TOPO_METH_NVL2STR, out)); 123 124 if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL) 125 return (set_error(thp, ETOPO_NOMEM, err, 126 TOPO_METH_NVL2STR, out)); 127 128 nvlist_free(out); 129 130 return (0); 131 } 132 133 int 134 topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri, 135 int *err) 136 { 137 char *f, buf[PATH_MAX]; 138 nvlist_t *out = NULL, *in = NULL; 139 tnode_t *rnode; 140 141 (void) strlcpy(buf, fmristr, sizeof (buf)); 142 if ((f = strchr(buf, ':')) == NULL) 143 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 144 TOPO_METH_STR2NVL, in)); 145 146 *f = '\0'; /* strip trailing FMRI path */ 147 148 if ((rnode = topo_hdl_root(thp, buf)) == NULL) 149 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 150 TOPO_METH_STR2NVL, in)); 151 152 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 153 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 154 in)); 155 156 if (nvlist_add_string(in, "fmri-string", fmristr) != 0) 157 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 158 in)); 159 160 if (topo_method_invoke(rnode, TOPO_METH_STR2NVL, 161 TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0) 162 return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in)); 163 164 nvlist_free(in); 165 166 if (out == NULL || 167 topo_hdl_nvdup(thp, out, fmri) != 0) 168 return (set_error(thp, ETOPO_FMRI_NVL, err, 169 TOPO_METH_STR2NVL, out)); 170 171 nvlist_free(out); 172 173 return (0); 174 } 175 176 int 177 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) 178 { 179 uint32_t present = 0; 180 char *scheme; 181 nvlist_t *out = NULL; 182 tnode_t *rnode; 183 184 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 185 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 186 TOPO_METH_PRESENT, out)); 187 188 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 189 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 190 TOPO_METH_PRESENT, out)); 191 192 if (topo_method_invoke(rnode, TOPO_METH_PRESENT, 193 TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) { 194 (void) set_error(thp, *err, err, TOPO_METH_PRESENT, out); 195 return (present); 196 } 197 198 (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present); 199 nvlist_free(out); 200 201 return (present); 202 } 203 204 int 205 topo_fmri_replaced(topo_hdl_t *thp, nvlist_t *fmri, int *err) 206 { 207 uint32_t replaced = FMD_OBJ_STATE_NOT_PRESENT; 208 char *scheme; 209 nvlist_t *out = NULL; 210 tnode_t *rnode; 211 212 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 213 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 214 TOPO_METH_REPLACED, out)); 215 216 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 217 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 218 TOPO_METH_REPLACED, out)); 219 220 if (topo_method_invoke(rnode, TOPO_METH_REPLACED, 221 TOPO_METH_REPLACED_VERSION, fmri, &out, err) < 0) { 222 (void) set_error(thp, *err, err, TOPO_METH_REPLACED, out); 223 return (FMD_OBJ_STATE_UNKNOWN); 224 } 225 226 (void) nvlist_lookup_uint32(out, TOPO_METH_REPLACED_RET, &replaced); 227 nvlist_free(out); 228 229 return (replaced); 230 } 231 232 int 233 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) 234 { 235 uint32_t contains; 236 char *scheme; 237 nvlist_t *in = NULL, *out = NULL; 238 tnode_t *rnode; 239 240 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 241 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 242 TOPO_METH_CONTAINS, NULL)); 243 244 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 245 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 246 TOPO_METH_CONTAINS, NULL)); 247 248 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 249 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 250 NULL)); 251 252 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 || 253 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0) 254 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 255 in)); 256 257 if (topo_method_invoke(rnode, TOPO_METH_CONTAINS, 258 TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) 259 return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in)); 260 261 (void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains); 262 nvlist_free(in); 263 nvlist_free(out); 264 265 return (contains); 266 } 267 268 int 269 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) 270 { 271 char *scheme; 272 uint32_t unusable = 0; 273 nvlist_t *out = NULL; 274 tnode_t *rnode; 275 276 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 277 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 278 TOPO_METH_UNUSABLE, out)); 279 280 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 281 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 282 TOPO_METH_UNUSABLE, out)); 283 284 if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE, 285 TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0) 286 return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out)); 287 288 (void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable); 289 nvlist_free(out); 290 291 return (unusable); 292 } 293 294 int 295 topo_fmri_retire(topo_hdl_t *thp, nvlist_t *fmri, int *err) 296 { 297 char *scheme; 298 uint32_t status; 299 nvlist_t *out = NULL; 300 tnode_t *rnode; 301 302 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 303 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 304 TOPO_METH_RETIRE, out)); 305 306 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 307 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 308 TOPO_METH_RETIRE, out)); 309 310 if (topo_method_invoke(rnode, TOPO_METH_RETIRE, 311 TOPO_METH_RETIRE_VERSION, fmri, &out, err) < 0) 312 return (set_error(thp, *err, err, TOPO_METH_RETIRE, out)); 313 314 if (nvlist_lookup_uint32(out, TOPO_METH_RETIRE_RET, &status) != 0) 315 return (set_error(thp, ETOPO_METHOD_FAIL, err, 316 TOPO_METH_RETIRE, out)); 317 nvlist_free(out); 318 319 return (status); 320 } 321 322 int 323 topo_fmri_unretire(topo_hdl_t *thp, nvlist_t *fmri, int *err) 324 { 325 char *scheme; 326 uint32_t status; 327 nvlist_t *out = NULL; 328 tnode_t *rnode; 329 330 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 331 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 332 TOPO_METH_UNRETIRE, out)); 333 334 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 335 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 336 TOPO_METH_UNRETIRE, out)); 337 338 if (topo_method_invoke(rnode, TOPO_METH_UNRETIRE, 339 TOPO_METH_UNRETIRE_VERSION, fmri, &out, err) < 0) 340 return (set_error(thp, *err, err, TOPO_METH_UNRETIRE, out)); 341 342 if (nvlist_lookup_uint32(out, TOPO_METH_UNRETIRE_RET, &status) != 0) { 343 nvlist_free(out); 344 return (set_error(thp, ETOPO_METHOD_FAIL, err, 345 TOPO_METH_UNRETIRE, out)); 346 } 347 nvlist_free(out); 348 349 return (status); 350 } 351 352 int 353 topo_fmri_service_state(topo_hdl_t *thp, nvlist_t *fmri, int *err) 354 { 355 char *scheme; 356 uint32_t service_state = FMD_SERVICE_STATE_UNKNOWN; 357 nvlist_t *out = NULL; 358 tnode_t *rnode; 359 360 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 361 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 362 TOPO_METH_SERVICE_STATE, out)); 363 364 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 365 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 366 TOPO_METH_SERVICE_STATE, out)); 367 368 if (topo_method_invoke(rnode, TOPO_METH_SERVICE_STATE, 369 TOPO_METH_SERVICE_STATE_VERSION, fmri, &out, err) < 0) 370 return (set_error(thp, *err, err, TOPO_METH_SERVICE_STATE, 371 out)); 372 373 (void) nvlist_lookup_uint32(out, TOPO_METH_SERVICE_STATE_RET, 374 &service_state); 375 nvlist_free(out); 376 377 return (service_state); 378 } 379 380 int 381 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) 382 { 383 char *scheme; 384 nvlist_t *out = NULL; 385 tnode_t *rnode; 386 387 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 388 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 389 TOPO_METH_EXPAND, out)); 390 391 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 392 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 393 TOPO_METH_EXPAND, out)); 394 395 if (topo_method_invoke(rnode, TOPO_METH_EXPAND, 396 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) 397 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); 398 399 return (0); 400 } 401 402 static int 403 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 404 const char *pname, nvlist_t *args, nvlist_t **prop, 405 int *err) 406 { 407 int rv; 408 nvlist_t *in = NULL; 409 tnode_t *rnode; 410 char *scheme; 411 412 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 413 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 414 TOPO_METH_PROP_GET, in)); 415 416 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 417 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 418 TOPO_METH_PROP_GET, in)); 419 420 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 421 return (set_error(thp, ETOPO_FMRI_NVL, err, 422 TOPO_METH_PROP_GET, in)); 423 424 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 425 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 426 rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname); 427 if (args != NULL) 428 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 429 if (rv != 0) 430 return (set_error(thp, ETOPO_FMRI_NVL, err, 431 TOPO_METH_PROP_GET, in)); 432 433 *prop = NULL; 434 rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET, 435 TOPO_METH_PROP_GET_VERSION, in, prop, err); 436 437 nvlist_free(in); 438 439 if (rv != 0) 440 return (-1); /* *err is set for us */ 441 442 if (*prop == NULL) 443 return (set_error(thp, ETOPO_PROP_NOENT, err, 444 TOPO_METH_PROP_GET, NULL)); 445 return (0); 446 } 447 448 int 449 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 450 { 451 nvlist_t *ap, *prop = NULL; 452 453 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, 454 nvl, &prop, err) < 0) 455 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 456 457 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0) 458 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru", 459 prop)); 460 461 if (topo_hdl_nvdup(thp, ap, asru) < 0) 462 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru", 463 prop)); 464 465 nvlist_free(prop); 466 467 return (0); 468 } 469 470 int 471 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err) 472 { 473 nvlist_t *fp, *prop = NULL; 474 475 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, 476 nvl, &prop, err) < 0) 477 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 478 479 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0) 480 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru", 481 prop)); 482 483 if (topo_hdl_nvdup(thp, fp, fru) < 0) 484 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru", 485 prop)); 486 487 nvlist_free(prop); 488 489 return (0); 490 } 491 492 int 493 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err) 494 { 495 nvlist_t *prop = NULL; 496 char *lp; 497 498 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, 499 NULL, &prop, err) < 0) 500 return (set_error(thp, *err, err, "topo_fmri_label", NULL)); 501 502 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0) 503 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 504 prop)); 505 506 if ((*label = topo_hdl_strdup(thp, lp)) == NULL) 507 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label", 508 prop)); 509 510 nvlist_free(prop); 511 512 return (0); 513 } 514 515 int 516 topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err) 517 { 518 nvlist_t *prop = NULL; 519 char *sp; 520 521 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID, 522 NULL, &prop, err) < 0) 523 return (set_error(thp, *err, err, "topo_fmri_serial", NULL)); 524 525 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0) 526 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial", 527 prop)); 528 529 if ((*serial = topo_hdl_strdup(thp, sp)) == NULL) 530 return (set_error(thp, ETOPO_PROP_NOMEM, err, 531 "topo_fmri_serial", prop)); 532 533 nvlist_free(prop); 534 535 return (0); 536 } 537 538 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 539 const char *pname, nvlist_t *args, nvlist_t **prop, 540 int *err) 541 { 542 *prop = NULL; 543 544 return (fmri_prop(thp, nvl, pg, pname, args, prop, err)); 545 } 546 547 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 548 nvlist_t *prop, int flag, nvlist_t *args, int *err) 549 { 550 int rv; 551 nvlist_t *in = NULL, *out = NULL; 552 tnode_t *rnode; 553 char *scheme; 554 555 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 556 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 557 TOPO_METH_PROP_SET, in)); 558 559 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 560 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 561 TOPO_METH_PROP_SET, in)); 562 563 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 564 return (set_error(thp, ETOPO_FMRI_NVL, err, 565 TOPO_METH_PROP_SET, in)); 566 567 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl); 568 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg); 569 rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop); 570 rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag); 571 if (args != NULL) 572 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 573 if (rv != 0) 574 return (set_error(thp, ETOPO_FMRI_NVL, err, 575 TOPO_METH_PROP_SET, in)); 576 577 rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET, 578 TOPO_METH_PROP_SET_VERSION, in, &out, err); 579 580 nvlist_free(in); 581 582 /* no return values */ 583 if (out != NULL) 584 nvlist_free(out); 585 586 if (rv) 587 return (-1); 588 589 return (0); 590 591 } 592 593 int 594 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 595 nvlist_t **pgroup, int *err) 596 { 597 int rv; 598 nvlist_t *in = NULL; 599 tnode_t *rnode; 600 char *scheme; 601 602 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 603 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 604 TOPO_METH_PROP_GET, in)); 605 606 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 607 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 608 TOPO_METH_PROP_GET, in)); 609 610 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 611 return (set_error(thp, ETOPO_FMRI_NVL, err, 612 TOPO_METH_PROP_GET, in)); 613 614 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 615 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 616 if (rv != 0) 617 return (set_error(thp, ETOPO_FMRI_NVL, err, 618 TOPO_METH_PROP_GET, in)); 619 620 *pgroup = NULL; 621 rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET, 622 TOPO_METH_PGRP_GET_VERSION, in, pgroup, err); 623 624 nvlist_free(in); 625 626 if (rv != 0) 627 return (-1); /* *err is set for us */ 628 629 if (*pgroup == NULL) 630 return (set_error(thp, ETOPO_PROP_NOENT, err, 631 TOPO_METH_PROP_GET, NULL)); 632 return (0); 633 } 634 635 int 636 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 637 { 638 uint32_t compare; 639 char *scheme1, *scheme2; 640 nvlist_t *in; 641 nvlist_t *out = NULL; 642 tnode_t *rnode; 643 644 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 645 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 646 TOPO_METH_COMPARE, NULL)); 647 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 648 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 649 TOPO_METH_COMPARE, NULL)); 650 651 if (strcmp(scheme1, scheme2) != 0) 652 return (0); 653 654 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 655 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 656 TOPO_METH_COMPARE, NULL)); 657 658 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 659 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 660 NULL)); 661 662 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 || 663 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0) 664 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 665 in)); 666 667 if (topo_method_invoke(rnode, TOPO_METH_COMPARE, 668 TOPO_METH_COMPARE_VERSION, in, &out, err) < 0) 669 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 670 671 (void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare); 672 nvlist_free(out); 673 nvlist_free(in); 674 675 return (compare); 676 } 677 678 /* 679 * topo_fmri_create 680 * 681 * If possible, creates an FMRI of the requested version in the 682 * requested scheme. Args are passed as part of the inputs to the 683 * fmri-create method of the scheme. 684 */ 685 nvlist_t * 686 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 687 topo_instance_t inst, nvlist_t *nvl, int *err) 688 { 689 nvlist_t *ins; 690 nvlist_t *out; 691 tnode_t *rnode; 692 693 ins = out = NULL; 694 695 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 696 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 697 TOPO_METH_FMRI, NULL)); 698 699 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 700 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 701 TOPO_METH_FMRI, NULL)); 702 703 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 704 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 705 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 706 TOPO_METH_FMRI, ins)); 707 } 708 709 if (nvl != NULL && 710 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 711 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 712 TOPO_METH_FMRI, ins)); 713 } 714 if (topo_method_invoke(rnode, 715 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 716 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 717 } 718 nvlist_free(ins); 719 return (out); 720 } 721 722 /* 723 * These private utility functions are used by fmd to maintain its resource 724 * cache. Because hc instance numbers are not guaranteed, it's possible to 725 * have two different FMRI strings represent the same logical entity. These 726 * functions hide this implementation detail from unknowing consumers such as 727 * fmd. 728 * 729 * Ideally, we'd like to do a str2nvl() and then a full FMRI hash and 730 * comparison, but these functions are designed to be fast and efficient. 731 * Given that there is only a single hc node that has this property 732 * (ses-enclosure), we hard-code this behavior here. If there are more 733 * instances of this behavior in the future, this function could be made more 734 * generic. 735 */ 736 static ulong_t 737 topo_fmri_strhash_one(const char *fmri, size_t len) 738 { 739 ulong_t g, h = 0; 740 size_t i; 741 742 for (i = 0; i < len; i++) { 743 h = (h << 4) + fmri[i]; 744 745 if ((g = (h & 0xf0000000)) != 0) { 746 h ^= (g >> 24); 747 h ^= g; 748 } 749 } 750 751 return (h); 752 } 753 754 /*ARGSUSED*/ 755 ulong_t 756 topo_fmri_strhash(topo_hdl_t *thp, const char *fmri) 757 { 758 char *e; 759 ulong_t h; 760 761 if (strncmp(fmri, "hc://", 5) != 0 || 762 (e = strstr(fmri, SES_ENCLOSURE)) == NULL) 763 return (topo_fmri_strhash_one(fmri, strlen(fmri))); 764 765 h = topo_fmri_strhash_one(fmri, e - fmri); 766 e += sizeof (SES_ENCLOSURE); 767 768 while (isdigit(*e)) 769 e++; 770 771 h += topo_fmri_strhash_one(e, strlen(e)); 772 773 return (h); 774 } 775 776 /*ARGSUSED*/ 777 boolean_t 778 topo_fmri_strcmp(topo_hdl_t *thp, const char *a, const char *b) 779 { 780 char *ea, *eb; 781 782 if (strncmp(a, "hc://", 5) != 0 || 783 strncmp(b, "hc://", 5) != 0 || 784 (ea = strstr(a, SES_ENCLOSURE)) == NULL || 785 (eb = strstr(b, SES_ENCLOSURE)) == NULL) 786 return (strcmp(a, b) == 0); 787 788 if ((ea - a) != (eb - b)) 789 return (B_FALSE); 790 791 if (strncmp(a, b, ea - a) != 0) 792 return (B_FALSE); 793 794 ea += sizeof (SES_ENCLOSURE); 795 eb += sizeof (SES_ENCLOSURE); 796 797 while (isdigit(*ea)) 798 ea++; 799 while (isdigit(*eb)) 800 eb++; 801 802 return (strcmp(ea, eb) == 0); 803 } 804 805 int 806 topo_fmri_facility(topo_hdl_t *thp, nvlist_t *rsrc, const char *fac_type, 807 uint32_t fac_subtype, topo_walk_cb_t cb, void *cb_args, int *err) 808 { 809 int rv; 810 nvlist_t *in = NULL, *out; 811 tnode_t *rnode; 812 char *scheme; 813 814 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 815 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 816 TOPO_METH_PROP_GET, in)); 817 818 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 819 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 820 TOPO_METH_PROP_GET, in)); 821 822 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 823 return (set_error(thp, ETOPO_FMRI_NVL, err, 824 TOPO_METH_PROP_GET, in)); 825 826 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 827 rv |= nvlist_add_string(in, FM_FMRI_FACILITY_TYPE, fac_type); 828 rv |= nvlist_add_uint32(in, "type", fac_subtype); 829 #ifdef _LP64 830 rv |= nvlist_add_uint64(in, "callback", (uint64_t)cb); 831 rv |= nvlist_add_uint64(in, "callback-args", (uint64_t)cb_args); 832 #else 833 rv |= nvlist_add_uint32(in, "callback", (uint32_t)cb); 834 rv |= nvlist_add_uint32(in, "callback-args", (uint32_t)cb_args); 835 #endif 836 if (rv != 0) 837 return (set_error(thp, ETOPO_FMRI_NVL, err, 838 TOPO_METH_PROP_GET, in)); 839 840 rv = topo_method_invoke(rnode, TOPO_METH_FACILITY, 841 TOPO_METH_FACILITY_VERSION, in, &out, err); 842 843 nvlist_free(in); 844 845 if (rv != 0) 846 return (-1); /* *err is set for us */ 847 848 return (0); 849 } 850