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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <string.h> 30 #include <limits.h> 31 #include <fm/topo_mod.h> 32 #include <sys/fm/protocol.h> 33 #include <topo_alloc.h> 34 #include <topo_error.h> 35 #include <topo_method.h> 36 #include <topo_subr.h> 37 #include <topo_string.h> 38 39 /*ARGSUSED*/ 40 static int 41 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 42 { 43 if (nvlp != NULL) 44 nvlist_free(nvlp); 45 46 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 47 topo_strerror(err)); 48 49 *errp = err; 50 return (-1); 51 } 52 53 /*ARGSUSED*/ 54 static nvlist_t * 55 set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 56 { 57 if (nvlp != NULL) 58 nvlist_free(nvlp); 59 60 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 61 topo_strerror(err)); 62 63 *errp = err; 64 return (NULL); 65 } 66 67 int 68 topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err) 69 { 70 char *scheme, *str; 71 nvlist_t *out = NULL; 72 tnode_t *rnode; 73 74 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 75 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 76 TOPO_METH_NVL2STR, out)); 77 78 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 79 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 80 TOPO_METH_NVL2STR, out)); 81 82 if (topo_method_invoke(rnode, TOPO_METH_NVL2STR, 83 TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0) 84 return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out)); 85 86 if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0) 87 return (set_error(thp, ETOPO_METHOD_INVAL, err, 88 TOPO_METH_NVL2STR, out)); 89 90 if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL) 91 return (set_error(thp, ETOPO_NOMEM, err, 92 TOPO_METH_NVL2STR, out)); 93 94 nvlist_free(out); 95 96 return (0); 97 } 98 99 int 100 topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri, 101 int *err) 102 { 103 char *f, buf[PATH_MAX]; 104 nvlist_t *out = NULL, *in = NULL; 105 tnode_t *rnode; 106 107 (void) strlcpy(buf, fmristr, sizeof (buf)); 108 if ((f = strchr(buf, ':')) == NULL) 109 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 110 TOPO_METH_STR2NVL, in)); 111 112 *f = '\0'; /* strip trailing FMRI path */ 113 114 if ((rnode = topo_hdl_root(thp, buf)) == NULL) 115 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 116 TOPO_METH_STR2NVL, in)); 117 118 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 119 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 120 in)); 121 122 if (nvlist_add_string(in, "fmri-string", fmristr) != 0) 123 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 124 in)); 125 126 if (topo_method_invoke(rnode, TOPO_METH_STR2NVL, 127 TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0) 128 return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in)); 129 130 if (out == NULL || 131 topo_hdl_nvdup(thp, out, fmri) != 0) 132 return (set_error(thp, ETOPO_FMRI_NVL, err, 133 TOPO_METH_STR2NVL, in)); 134 135 nvlist_free(out); 136 nvlist_free(in); 137 138 return (0); 139 } 140 141 /* ARGSUSED */ 142 static int 143 is_present(topo_hdl_t *thp, tnode_t *node, void *data) 144 { 145 int err; 146 uint32_t present = 0; 147 nvlist_t *out = NULL; 148 nvlist_t *fmri = (nvlist_t *)data; 149 150 if (topo_method_invoke(node, TOPO_METH_PRESENT, 151 TOPO_METH_PRESENT_VERSION, fmri, &out, &err) < 0) { 152 if (out != NULL) 153 nvlist_free(out); 154 return (present); 155 } 156 157 (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present); 158 159 nvlist_free(out); 160 161 return (present); 162 } 163 164 int 165 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) 166 { 167 int ret = 0; 168 uint32_t present = 0; 169 char *scheme; 170 nvlist_t *out = NULL; 171 tnode_t *rnode; 172 173 if (topo_fmri_invoke(thp, fmri, is_present, fmri, &ret) == 0) 174 return (ret); 175 176 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 177 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 178 TOPO_METH_PRESENT, out)); 179 180 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 181 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 182 TOPO_METH_PRESENT, out)); 183 184 if (topo_method_invoke(rnode, TOPO_METH_PRESENT, 185 TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) { 186 (void) set_error(thp, *err, err, TOPO_METH_PRESENT, out); 187 return (present); 188 } 189 190 (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present); 191 nvlist_free(out); 192 193 return (present); 194 } 195 196 int 197 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) 198 { 199 int rc; 200 char *scheme; 201 nvlist_t *in, *out = NULL; 202 tnode_t *rnode; 203 204 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 205 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 206 TOPO_METH_CONTAINS, out)); 207 208 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 209 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 210 TOPO_METH_CONTAINS, out)); 211 212 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 213 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 214 out)); 215 216 if (nvlist_add_nvlist(in, "fmri", fmri) != 0 || 217 nvlist_add_nvlist(in, "subfmri", subfmri) != 0) 218 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 219 out)); 220 221 if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0) 222 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 223 out)); 224 225 if ((rc = topo_method_invoke(rnode, TOPO_METH_CONTAINS, 226 TOPO_METH_CONTAINS_VERSION, fmri, &out, err)) < 0) 227 return (set_error(thp, *err, err, TOPO_METH_CONTAINS, out)); 228 229 return (rc); 230 } 231 232 int 233 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) 234 { 235 char *scheme; 236 uint32_t unusable = 0; 237 nvlist_t *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_UNUSABLE, out)); 243 244 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 245 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 246 TOPO_METH_UNUSABLE, out)); 247 248 if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE, 249 TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0) 250 return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out)); 251 252 (void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable); 253 nvlist_free(out); 254 255 return (unusable); 256 } 257 258 int 259 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) 260 { 261 char *scheme; 262 nvlist_t *out = NULL; 263 tnode_t *rnode; 264 265 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 266 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 267 TOPO_METH_EXPAND, out)); 268 269 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 270 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 271 TOPO_METH_EXPAND, out)); 272 273 if (topo_method_invoke(rnode, TOPO_METH_EXPAND, 274 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) 275 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); 276 277 return (0); 278 } 279 280 struct prop_lookup { 281 int pl_err; 282 topo_type_t pl_type; 283 const char *pl_group; 284 const char *pl_name; 285 nvlist_t **pl_prop; 286 nvlist_t *pl_resource; 287 }; 288 289 static int 290 prop_lookup(topo_hdl_t *thp, tnode_t *node, void *pdata) 291 { 292 int rc; 293 nvlist_t *r1; 294 struct prop_lookup *plp = (struct prop_lookup *)pdata; 295 296 if (topo_node_resource(node, &r1, &plp->pl_err) != 0) 297 return (TOPO_WALK_ERR); 298 299 rc = topo_fmri_compare(thp, r1, plp->pl_resource, &plp->pl_err); 300 nvlist_free(r1); 301 if (rc == 0) 302 return (TOPO_WALK_NEXT); 303 if (rc < 0) 304 return (TOPO_WALK_ERR); 305 306 /* 307 * Special case for dynamically created ASRU and FRU 308 */ 309 if (strcmp(plp->pl_group, TOPO_PGROUP_PROTOCOL) == 0) { 310 if (strcmp(plp->pl_name, TOPO_PROP_ASRU) == 0) { 311 if (topo_node_asru(node, plp->pl_prop, plp->pl_resource, 312 &plp->pl_err) < 0) { 313 return (TOPO_WALK_ERR); 314 } 315 return (0); 316 } else if (strcmp(plp->pl_name, TOPO_PROP_FRU) == 0) { 317 if (topo_node_fru(node, plp->pl_prop, plp->pl_resource, 318 &plp->pl_err) < 0) { 319 return (TOPO_WALK_ERR); 320 } 321 return (0); 322 } 323 } 324 325 switch (plp->pl_type) { 326 case TOPO_TYPE_STRING: 327 { 328 char *str; 329 if (topo_prop_get_string(node, plp->pl_group, 330 plp->pl_name, &str, &plp->pl_err) < 0) 331 return (TOPO_WALK_ERR); 332 333 if (nvlist_add_string(*plp->pl_prop, "prop", str) 334 != 0) { 335 topo_hdl_strfree(thp, str); 336 plp->pl_err = ETOPO_PROP_NVL; 337 return (TOPO_WALK_ERR); 338 } 339 topo_hdl_strfree(thp, str); 340 return (TOPO_WALK_TERMINATE); 341 } 342 default: 343 plp->pl_err = ETOPO_PROP_TYPE; 344 return (TOPO_WALK_ERR); 345 } 346 347 } 348 349 static int 350 fmri_prop(topo_hdl_t *thp, nvlist_t *resource, const char *pgname, 351 const char *pname, topo_type_t type, nvlist_t **prop, int *err) 352 { 353 int rc; 354 topo_walk_t *wp; 355 char *scheme; 356 struct prop_lookup pl; 357 358 if (nvlist_lookup_string(resource, FM_FMRI_SCHEME, &scheme) != 0) 359 return (set_error(thp, ETOPO_METHOD_INVAL, err, 360 "fmri_prop", NULL)); 361 362 *prop = NULL; 363 pl.pl_resource = resource; 364 pl.pl_err = 0; 365 pl.pl_type = type; 366 pl.pl_group = pgname; 367 pl.pl_name = pname; 368 pl.pl_prop = prop; 369 if ((wp = topo_walk_init(thp, scheme, prop_lookup, &pl, err)) == NULL) 370 return (set_error(thp, pl.pl_err, err, "fmri_prop", NULL)); 371 372 rc = topo_walk_step(wp, TOPO_WALK_CHILD); 373 topo_walk_fini(wp); 374 375 if (rc == TOPO_WALK_ERR) { 376 return (set_error(thp, pl.pl_err, err, "fmri_prop", NULL)); 377 } 378 379 /* 380 * Walk terminated without finding resource or property 381 */ 382 if (*prop == NULL) 383 return (set_error(thp, ETOPO_PROP_NOENT, err, "fmri_prop", 384 NULL)); 385 386 return (0); 387 } 388 389 int 390 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 391 { 392 393 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, 394 TOPO_TYPE_FMRI, asru, err) < 0) 395 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 396 397 return (0); 398 } 399 400 int 401 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err) 402 { 403 404 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, 405 TOPO_TYPE_FMRI, fru, err) < 0) 406 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 407 408 return (0); 409 } 410 411 int 412 topo_fmri_label(topo_hdl_t *thp, nvlist_t *fmri, char **label, int *err) 413 { 414 nvlist_t *nvl, *fru; 415 char *str; 416 417 if (topo_fmri_fru(thp, fmri, &fru, err) < 0) 418 return (set_error(thp, *err, err, "topo_fmri_label", NULL)); 419 420 if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) 421 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 422 NULL)); 423 424 if (fmri_prop(thp, fru, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, 425 TOPO_TYPE_STRING, &nvl, err) < 0) { 426 nvlist_free(fru); 427 return (set_error(thp, *err, err, "topo_fmri_label", nvl)); 428 } 429 430 nvlist_free(fru); 431 432 if (nvlist_lookup_string(nvl, "prop", &str) != 0) 433 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 434 nvl)); 435 436 if ((*label = topo_hdl_strdup(thp, str)) == NULL) 437 return (set_error(thp, ETOPO_PROP_NOMEM, err, 438 "topo_fmri_label", nvl)); 439 440 nvlist_free(nvl); 441 442 return (0); 443 } 444 445 int 446 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 447 { 448 int rc; 449 char *scheme1, *scheme2; 450 nvlist_t *in; 451 nvlist_t *out = NULL; 452 tnode_t *rnode; 453 454 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 455 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 456 TOPO_METH_COMPARE, NULL)); 457 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 458 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 459 TOPO_METH_COMPARE, NULL)); 460 461 if (strcmp(scheme1, scheme2) != 0) 462 return (0); 463 464 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 465 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 466 TOPO_METH_COMPARE, NULL)); 467 468 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 469 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 470 NULL)); 471 472 if (nvlist_add_nvlist(in, "nv1", f1) != 0 || 473 nvlist_add_nvlist(in, "nv2", f2) != 0) 474 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 475 in)); 476 477 if ((rc = topo_method_invoke(rnode, TOPO_METH_COMPARE, 478 TOPO_METH_COMPARE_VERSION, in, &out, err)) < 0) 479 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 480 481 nvlist_free(in); 482 483 return (rc); 484 } 485 486 struct topo_invoke { 487 nvlist_t *tl_resource; 488 topo_walk_cb_t tl_func; 489 int tl_ret; 490 void *tl_pdata; 491 }; 492 493 static int 494 walk_invoke(topo_hdl_t *thp, tnode_t *node, void *pdata) 495 { 496 int rc; 497 struct topo_invoke *tlp = (struct topo_invoke *)pdata; 498 nvlist_t *r1, *r2 = tlp->tl_resource; 499 500 if (topo_node_resource(node, &r1, &tlp->tl_ret) != 0) 501 return (TOPO_WALK_ERR); 502 503 rc = topo_fmri_compare(thp, r1, r2, &tlp->tl_ret); 504 nvlist_free(r1); 505 if (rc == 0) 506 return (TOPO_WALK_NEXT); 507 else if (rc == -1) 508 return (TOPO_WALK_ERR); 509 510 tlp->tl_ret = tlp->tl_func(thp, node, tlp->tl_pdata); 511 512 return (TOPO_WALK_TERMINATE); 513 } 514 515 int 516 topo_fmri_invoke(topo_hdl_t *thp, nvlist_t *nvl, topo_walk_cb_t cb_f, 517 void *pdata, int *ret) 518 { 519 int err; 520 topo_walk_t *wp; 521 char *scheme; 522 struct topo_invoke tl; 523 524 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 525 return (set_error(thp, ETOPO_METHOD_INVAL, ret, 526 "topo_fmri_invoke", NULL)); 527 528 tl.tl_resource = nvl; 529 tl.tl_func = cb_f; 530 tl.tl_pdata = pdata; 531 tl.tl_ret = 0; 532 if ((wp = topo_walk_init(thp, scheme, walk_invoke, &tl, &err)) == NULL) 533 return (set_error(thp, err, ret, "topo_fmri_invoke", NULL)); 534 535 err = topo_walk_step(wp, TOPO_WALK_CHILD); 536 topo_walk_fini(wp); 537 538 if (err == TOPO_WALK_ERR) { 539 *ret = err; 540 return (-1); 541 } 542 543 *ret = tl.tl_ret; 544 545 return (0); 546 } 547 548 /* 549 * topo_fmri_create 550 * 551 * If possible, creates an FMRI of the requested version in the 552 * requested scheme. Args are passed as part of the inputs to the 553 * fmri-create method of the scheme. 554 */ 555 nvlist_t * 556 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 557 topo_instance_t inst, nvlist_t *nvl, int *err) 558 { 559 nvlist_t *ins; 560 nvlist_t *out; 561 tnode_t *rnode; 562 563 ins = out = NULL; 564 565 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 566 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 567 TOPO_METH_FMRI, NULL)); 568 569 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 570 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 571 TOPO_METH_FMRI, NULL)); 572 573 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 574 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 575 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 576 TOPO_METH_FMRI, ins)); 577 } 578 579 if (nvl != NULL && 580 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 581 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 582 TOPO_METH_FMRI, ins)); 583 } 584 if (topo_method_invoke(rnode, 585 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 586 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 587 } 588 nvlist_free(ins); 589 return (out); 590 } 591