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 /* 40 * Topology node properties and method operations may be accessed by FMRI. 41 * The FMRI used to perform property look-ups and method operations is 42 * the FMRI contained in the matching topology node's protocol property 43 * grouping for the resource property. The full range of fmd(1M) 44 * scheme plugin operations are supported as long as a backend method is 45 * supplied by a scheme-specific enumerator or the enumerator module that 46 * created the matching topology node. Support for fmd scheme operations 47 * include: 48 * 49 * - expand 50 * - present 51 * - contains 52 * - unusable 53 * - nvl2str 54 * 55 * In addition, the following operations are supported per-FMRI: 56 * 57 * - str2nvl: convert string-based FMRI to nvlist 58 * - compare: compare two FMRIs 59 * - asru: lookup associated ASRU property by FMRI 60 * - fru: lookup associated FRU by FMRI 61 * - create: an FMRI nvlist by scheme type 62 * - propery lookup 63 * 64 * These routines may only be called by consumers of a topology snapshot. 65 * They may not be called by libtopo enumerator or method modules. 66 */ 67 68 /*ARGSUSED*/ 69 static int 70 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 71 { 72 if (nvlp != NULL) 73 nvlist_free(nvlp); 74 75 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 76 topo_strerror(err)); 77 78 *errp = err; 79 return (-1); 80 } 81 82 /*ARGSUSED*/ 83 static nvlist_t * 84 set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 85 { 86 if (nvlp != NULL) 87 nvlist_free(nvlp); 88 89 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 90 topo_strerror(err)); 91 92 *errp = err; 93 return (NULL); 94 } 95 96 int 97 topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err) 98 { 99 char *scheme, *str; 100 nvlist_t *out = NULL; 101 tnode_t *rnode; 102 103 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 104 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 105 TOPO_METH_NVL2STR, out)); 106 107 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 108 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 109 TOPO_METH_NVL2STR, out)); 110 111 if (topo_method_invoke(rnode, TOPO_METH_NVL2STR, 112 TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0) 113 return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out)); 114 115 if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0) 116 return (set_error(thp, ETOPO_METHOD_INVAL, err, 117 TOPO_METH_NVL2STR, out)); 118 119 if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL) 120 return (set_error(thp, ETOPO_NOMEM, err, 121 TOPO_METH_NVL2STR, out)); 122 123 nvlist_free(out); 124 125 return (0); 126 } 127 128 int 129 topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri, 130 int *err) 131 { 132 char *f, buf[PATH_MAX]; 133 nvlist_t *out = NULL, *in = NULL; 134 tnode_t *rnode; 135 136 (void) strlcpy(buf, fmristr, sizeof (buf)); 137 if ((f = strchr(buf, ':')) == NULL) 138 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 139 TOPO_METH_STR2NVL, in)); 140 141 *f = '\0'; /* strip trailing FMRI path */ 142 143 if ((rnode = topo_hdl_root(thp, buf)) == NULL) 144 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 145 TOPO_METH_STR2NVL, in)); 146 147 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 148 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 149 in)); 150 151 if (nvlist_add_string(in, "fmri-string", fmristr) != 0) 152 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 153 in)); 154 155 if (topo_method_invoke(rnode, TOPO_METH_STR2NVL, 156 TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0) 157 return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in)); 158 159 nvlist_free(in); 160 161 if (out == NULL || 162 topo_hdl_nvdup(thp, out, fmri) != 0) 163 return (set_error(thp, ETOPO_FMRI_NVL, err, 164 TOPO_METH_STR2NVL, out)); 165 166 nvlist_free(out); 167 168 return (0); 169 } 170 171 int 172 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) 173 { 174 uint32_t present = 0; 175 char *scheme; 176 nvlist_t *out = NULL; 177 tnode_t *rnode; 178 179 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 180 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 181 TOPO_METH_PRESENT, out)); 182 183 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 184 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 185 TOPO_METH_PRESENT, out)); 186 187 if (topo_method_invoke(rnode, TOPO_METH_PRESENT, 188 TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) { 189 (void) set_error(thp, *err, err, TOPO_METH_PRESENT, out); 190 return (present); 191 } 192 193 (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present); 194 nvlist_free(out); 195 196 return (present); 197 } 198 199 int 200 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) 201 { 202 uint32_t contains; 203 char *scheme; 204 nvlist_t *in = NULL, *out = NULL; 205 tnode_t *rnode; 206 207 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 208 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 209 TOPO_METH_CONTAINS, NULL)); 210 211 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 212 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 213 TOPO_METH_CONTAINS, NULL)); 214 215 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 216 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 217 NULL)); 218 219 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 || 220 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0) 221 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 222 in)); 223 224 if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0) 225 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 226 out)); 227 228 if (topo_method_invoke(rnode, TOPO_METH_CONTAINS, 229 TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) { 230 nvlist_free(out); 231 return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in)); 232 } 233 234 (void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains); 235 nvlist_free(in); 236 nvlist_free(out); 237 238 return (contains); 239 } 240 241 int 242 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) 243 { 244 char *scheme; 245 uint32_t unusable = 0; 246 nvlist_t *out = NULL; 247 tnode_t *rnode; 248 249 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 250 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 251 TOPO_METH_UNUSABLE, out)); 252 253 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 254 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 255 TOPO_METH_UNUSABLE, out)); 256 257 if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE, 258 TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0) 259 return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out)); 260 261 (void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable); 262 nvlist_free(out); 263 264 return (unusable); 265 } 266 267 int 268 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) 269 { 270 char *scheme; 271 nvlist_t *out = NULL; 272 tnode_t *rnode; 273 274 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 275 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 276 TOPO_METH_EXPAND, out)); 277 278 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 279 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 280 TOPO_METH_EXPAND, out)); 281 282 if (topo_method_invoke(rnode, TOPO_METH_EXPAND, 283 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) 284 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); 285 286 return (0); 287 } 288 289 static int 290 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 291 const char *pname, nvlist_t *args, nvlist_t **prop, 292 int *err) 293 { 294 int rv; 295 nvlist_t *in = NULL; 296 tnode_t *rnode; 297 char *scheme; 298 299 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 300 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 301 TOPO_METH_PROP_GET, in)); 302 303 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 304 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 305 TOPO_METH_PROP_GET, in)); 306 307 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 308 return (set_error(thp, ETOPO_FMRI_NVL, err, 309 TOPO_METH_PROP_GET, in)); 310 311 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 312 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 313 rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname); 314 if (args != NULL) 315 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 316 if (rv != 0) 317 return (set_error(thp, ETOPO_FMRI_NVL, err, 318 TOPO_METH_PROP_GET, in)); 319 320 *prop = NULL; 321 rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET, 322 TOPO_METH_PROP_GET_VERSION, in, prop, err); 323 324 nvlist_free(in); 325 326 if (rv != 0) 327 return (-1); /* *err is set for us */ 328 329 if (*prop == NULL) 330 return (set_error(thp, ETOPO_PROP_NOENT, err, 331 TOPO_METH_PROP_GET, NULL)); 332 return (0); 333 } 334 335 int 336 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 337 { 338 nvlist_t *ap, *prop = NULL; 339 340 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, 341 nvl, &prop, err) < 0) 342 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 343 344 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0) 345 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru", 346 prop)); 347 348 if (topo_hdl_nvdup(thp, ap, asru) < 0) 349 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru", 350 prop)); 351 352 nvlist_free(prop); 353 354 return (0); 355 } 356 357 int 358 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err) 359 { 360 nvlist_t *fp, *prop = NULL; 361 362 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, 363 nvl, &prop, err) < 0) 364 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 365 366 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0) 367 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru", 368 prop)); 369 370 if (topo_hdl_nvdup(thp, fp, fru) < 0) 371 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru", 372 prop)); 373 374 nvlist_free(prop); 375 376 return (0); 377 } 378 379 int 380 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err) 381 { 382 nvlist_t *prop = NULL; 383 char *lp; 384 385 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, 386 NULL, &prop, err) < 0) 387 return (set_error(thp, *err, err, "topo_fmri_label", NULL)); 388 389 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0) 390 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 391 prop)); 392 393 if ((*label = topo_hdl_strdup(thp, lp)) == NULL) 394 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label", 395 prop)); 396 397 nvlist_free(prop); 398 399 return (0); 400 } 401 402 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 403 const char *pname, nvlist_t *args, nvlist_t **prop, 404 int *err) 405 { 406 *prop = NULL; 407 408 return (fmri_prop(thp, nvl, pg, pname, args, prop, err)); 409 } 410 411 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 412 nvlist_t *prop, int flag, nvlist_t *args, int *err) 413 { 414 int rv; 415 nvlist_t *in = NULL, *out = NULL; 416 tnode_t *rnode; 417 char *scheme; 418 419 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 420 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 421 TOPO_METH_PROP_SET, in)); 422 423 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 424 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 425 TOPO_METH_PROP_SET, in)); 426 427 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 428 return (set_error(thp, ETOPO_FMRI_NVL, err, 429 TOPO_METH_PROP_SET, in)); 430 431 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl); 432 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg); 433 rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop); 434 rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag); 435 if (args != NULL) 436 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 437 if (rv != 0) 438 return (set_error(thp, ETOPO_FMRI_NVL, err, 439 TOPO_METH_PROP_SET, in)); 440 441 rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET, 442 TOPO_METH_PROP_SET_VERSION, in, &out, err); 443 444 nvlist_free(in); 445 446 /* no return values */ 447 if (out != NULL) 448 nvlist_free(out); 449 450 if (rv) 451 return (-1); 452 453 return (0); 454 455 } 456 457 int 458 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 459 nvlist_t **pgroup, int *err) 460 { 461 int rv; 462 nvlist_t *in = NULL; 463 tnode_t *rnode; 464 char *scheme; 465 466 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 467 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 468 TOPO_METH_PROP_GET, in)); 469 470 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 471 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 472 TOPO_METH_PROP_GET, in)); 473 474 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 475 return (set_error(thp, ETOPO_FMRI_NVL, err, 476 TOPO_METH_PROP_GET, in)); 477 478 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 479 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 480 if (rv != 0) 481 return (set_error(thp, ETOPO_FMRI_NVL, err, 482 TOPO_METH_PROP_GET, in)); 483 484 *pgroup = NULL; 485 rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET, 486 TOPO_METH_PGRP_GET_VERSION, in, pgroup, err); 487 488 nvlist_free(in); 489 490 if (rv != 0) 491 return (-1); /* *err is set for us */ 492 493 if (*pgroup == NULL) 494 return (set_error(thp, ETOPO_PROP_NOENT, err, 495 TOPO_METH_PROP_GET, NULL)); 496 return (0); 497 } 498 499 int 500 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 501 { 502 uint32_t compare; 503 char *scheme1, *scheme2; 504 nvlist_t *in; 505 nvlist_t *out = NULL; 506 tnode_t *rnode; 507 508 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 509 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 510 TOPO_METH_COMPARE, NULL)); 511 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 512 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 513 TOPO_METH_COMPARE, NULL)); 514 515 if (strcmp(scheme1, scheme2) != 0) 516 return (0); 517 518 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 519 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 520 TOPO_METH_COMPARE, NULL)); 521 522 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 523 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 524 NULL)); 525 526 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 || 527 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0) 528 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 529 in)); 530 531 if (topo_method_invoke(rnode, TOPO_METH_COMPARE, 532 TOPO_METH_COMPARE_VERSION, in, &out, err) < 0) 533 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 534 535 (void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare); 536 nvlist_free(out); 537 nvlist_free(in); 538 539 return (compare); 540 } 541 542 /* 543 * topo_fmri_create 544 * 545 * If possible, creates an FMRI of the requested version in the 546 * requested scheme. Args are passed as part of the inputs to the 547 * fmri-create method of the scheme. 548 */ 549 nvlist_t * 550 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 551 topo_instance_t inst, nvlist_t *nvl, int *err) 552 { 553 nvlist_t *ins; 554 nvlist_t *out; 555 tnode_t *rnode; 556 557 ins = out = NULL; 558 559 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 560 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 561 TOPO_METH_FMRI, NULL)); 562 563 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 564 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 565 TOPO_METH_FMRI, NULL)); 566 567 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 568 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 569 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 570 TOPO_METH_FMRI, ins)); 571 } 572 573 if (nvl != NULL && 574 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 575 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 576 TOPO_METH_FMRI, ins)); 577 } 578 if (topo_method_invoke(rnode, 579 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 580 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 581 } 582 nvlist_free(ins); 583 return (out); 584 } 585