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 2006 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 int rc; 236 char *scheme; 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 ((rc = 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 return (rc); 253 } 254 255 int 256 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) 257 { 258 char *scheme; 259 nvlist_t *out = NULL; 260 tnode_t *rnode; 261 262 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 263 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 264 TOPO_METH_EXPAND, out)); 265 266 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 267 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 268 TOPO_METH_EXPAND, out)); 269 270 if (topo_method_invoke(rnode, TOPO_METH_EXPAND, 271 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) 272 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); 273 274 return (0); 275 } 276 277 struct prop_lookup { 278 int pl_err; 279 topo_type_t pl_type; 280 const char *pl_group; 281 const char *pl_name; 282 nvlist_t **pl_prop; 283 nvlist_t *pl_resource; 284 }; 285 286 static int 287 prop_lookup(topo_hdl_t *thp, tnode_t *node, void *pdata) 288 { 289 int rc; 290 nvlist_t *r1; 291 struct prop_lookup *plp = (struct prop_lookup *)pdata; 292 293 if (topo_node_resource(node, &r1, &plp->pl_err) != 0) 294 return (TOPO_WALK_ERR); 295 296 rc = topo_fmri_compare(thp, r1, plp->pl_resource, &plp->pl_err); 297 nvlist_free(r1); 298 if (rc == 0) 299 return (TOPO_WALK_NEXT); 300 if (rc < 0) 301 return (TOPO_WALK_ERR); 302 303 /* 304 * Special case for dynamically created ASRU and FRU 305 */ 306 if (strcmp(plp->pl_group, TOPO_PGROUP_PROTOCOL) == 0) { 307 if (strcmp(plp->pl_name, TOPO_PROP_ASRU) == 0) { 308 if (topo_node_asru(node, plp->pl_prop, plp->pl_resource, 309 &plp->pl_err) < 0) { 310 return (TOPO_WALK_ERR); 311 } 312 return (0); 313 } else if (strcmp(plp->pl_name, TOPO_PROP_FRU) == 0) { 314 if (topo_node_fru(node, plp->pl_prop, plp->pl_resource, 315 &plp->pl_err) < 0) { 316 return (TOPO_WALK_ERR); 317 } 318 return (0); 319 } 320 } 321 322 switch (plp->pl_type) { 323 case TOPO_TYPE_STRING: 324 { 325 char *str; 326 if (topo_prop_get_string(node, plp->pl_group, 327 plp->pl_name, &str, &plp->pl_err) < 0) 328 return (TOPO_WALK_ERR); 329 330 if (nvlist_add_string(*plp->pl_prop, "prop", str) 331 != 0) { 332 topo_hdl_strfree(thp, str); 333 plp->pl_err = ETOPO_PROP_NVL; 334 return (TOPO_WALK_ERR); 335 } 336 topo_hdl_strfree(thp, str); 337 return (TOPO_WALK_TERMINATE); 338 } 339 default: 340 plp->pl_err = ETOPO_PROP_TYPE; 341 return (TOPO_WALK_ERR); 342 } 343 344 } 345 346 static int 347 fmri_prop(topo_hdl_t *thp, nvlist_t *resource, const char *pgname, 348 const char *pname, topo_type_t type, nvlist_t **prop, int *err) 349 { 350 int rc; 351 topo_walk_t *wp; 352 char *scheme; 353 struct prop_lookup pl; 354 355 if (nvlist_lookup_string(resource, FM_FMRI_SCHEME, &scheme) != 0) 356 return (set_error(thp, ETOPO_METHOD_INVAL, err, 357 "fmri_prop", NULL)); 358 359 pl.pl_resource = resource; 360 pl.pl_err = 0; 361 pl.pl_type = type; 362 pl.pl_group = pgname; 363 pl.pl_name = pname; 364 pl.pl_prop = prop; 365 if ((wp = topo_walk_init(thp, scheme, prop_lookup, &pl, err)) == NULL) 366 return (set_error(thp, pl.pl_err, err, "fmri_prop", NULL)); 367 368 rc = topo_walk_step(wp, TOPO_WALK_CHILD); 369 topo_walk_fini(wp); 370 371 if (rc == TOPO_WALK_ERR) { 372 return (set_error(thp, pl.pl_err, err, "fmri_prop", NULL)); 373 } 374 375 return (0); 376 } 377 378 int 379 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 380 { 381 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, 382 TOPO_TYPE_FMRI, asru, err) < 0) 383 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 384 385 return (0); 386 } 387 388 int 389 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err) 390 { 391 392 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, 393 TOPO_TYPE_FMRI, fru, err) < 0) 394 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 395 396 return (0); 397 } 398 399 int 400 topo_fmri_label(topo_hdl_t *thp, nvlist_t *fmri, char **label, int *err) 401 { 402 nvlist_t *nvl, *fru; 403 char *str; 404 405 if (topo_fmri_fru(thp, fmri, &fru, err) < 0) 406 return (set_error(thp, *err, err, "topo_fmri_label", NULL)); 407 408 if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) 409 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 410 NULL)); 411 412 if (fmri_prop(thp, fru, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, 413 TOPO_TYPE_STRING, &nvl, err) < 0) { 414 nvlist_free(fru); 415 return (set_error(thp, *err, err, "topo_fmri_label", nvl)); 416 } 417 418 nvlist_free(fru); 419 420 if (nvlist_lookup_string(nvl, "prop", &str) != 0) 421 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 422 nvl)); 423 424 if ((*label = topo_hdl_strdup(thp, str)) == NULL) 425 return (set_error(thp, ETOPO_PROP_NOMEM, err, 426 "topo_fmri_label", nvl)); 427 428 nvlist_free(nvl); 429 430 return (0); 431 } 432 433 int 434 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 435 { 436 int rc; 437 char *scheme1, *scheme2; 438 nvlist_t *in; 439 nvlist_t *out = NULL; 440 tnode_t *rnode; 441 442 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 443 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 444 TOPO_METH_COMPARE, NULL)); 445 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 446 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 447 TOPO_METH_COMPARE, NULL)); 448 449 if (strcmp(scheme1, scheme2) != 0) 450 return (0); 451 452 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 453 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 454 TOPO_METH_COMPARE, NULL)); 455 456 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 457 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 458 NULL)); 459 460 if (nvlist_add_nvlist(in, "nv1", f1) != 0 || 461 nvlist_add_nvlist(in, "nv2", f2) != 0) 462 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 463 in)); 464 465 if ((rc = topo_method_invoke(rnode, TOPO_METH_COMPARE, 466 TOPO_METH_COMPARE_VERSION, in, &out, err)) < 0) 467 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 468 469 nvlist_free(in); 470 471 return (rc); 472 } 473 474 struct topo_invoke { 475 nvlist_t *tl_resource; 476 topo_walk_cb_t tl_func; 477 int tl_ret; 478 void *tl_pdata; 479 }; 480 481 static int 482 walk_invoke(topo_hdl_t *thp, tnode_t *node, void *pdata) 483 { 484 int rc; 485 struct topo_invoke *tlp = (struct topo_invoke *)pdata; 486 nvlist_t *r1, *r2 = tlp->tl_resource; 487 488 if (topo_node_resource(node, &r1, &tlp->tl_ret) != 0) 489 return (TOPO_WALK_ERR); 490 491 rc = topo_fmri_compare(thp, r1, r2, &tlp->tl_ret); 492 nvlist_free(r1); 493 if (rc == 0) 494 return (TOPO_WALK_NEXT); 495 else if (rc == -1) 496 return (TOPO_WALK_ERR); 497 498 tlp->tl_ret = tlp->tl_func(thp, node, tlp->tl_pdata); 499 500 return (TOPO_WALK_TERMINATE); 501 } 502 503 int 504 topo_fmri_invoke(topo_hdl_t *thp, nvlist_t *nvl, topo_walk_cb_t cb_f, 505 void *pdata, int *ret) 506 { 507 int err; 508 topo_walk_t *wp; 509 char *scheme; 510 struct topo_invoke tl; 511 512 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 513 return (set_error(thp, ETOPO_METHOD_INVAL, ret, 514 "topo_fmri_invoke", NULL)); 515 516 tl.tl_resource = nvl; 517 tl.tl_func = cb_f; 518 tl.tl_pdata = pdata; 519 tl.tl_ret = 0; 520 if ((wp = topo_walk_init(thp, scheme, walk_invoke, &tl, &err)) == NULL) 521 return (set_error(thp, err, ret, "topo_fmri_invoke", NULL)); 522 523 err = topo_walk_step(wp, TOPO_WALK_CHILD); 524 topo_walk_fini(wp); 525 526 if (err == TOPO_WALK_ERR) { 527 *ret = err; 528 return (-1); 529 } 530 531 *ret = tl.tl_ret; 532 533 return (0); 534 } 535 536 /* 537 * topo_fmri_create 538 * 539 * If possible, creates an FMRI of the requested version in the 540 * requested scheme. Args are passed as part of the inputs to the 541 * fmri-create method of the scheme. 542 */ 543 nvlist_t * 544 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 545 topo_instance_t inst, nvlist_t *nvl, int *err) 546 { 547 nvlist_t *ins; 548 nvlist_t *out; 549 tnode_t *rnode; 550 551 ins = out = NULL; 552 553 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 554 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 555 TOPO_METH_FMRI, NULL)); 556 557 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 558 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 559 TOPO_METH_FMRI, NULL)); 560 561 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 562 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 563 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 564 TOPO_METH_FMRI, ins)); 565 } 566 567 if (nvl != NULL && 568 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 569 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 570 TOPO_METH_FMRI, ins)); 571 } 572 if (topo_method_invoke(rnode, 573 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 574 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 575 } 576 nvlist_free(ins); 577 return (out); 578 } 579