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 if (out == NULL || 160 topo_hdl_nvdup(thp, out, fmri) != 0) 161 return (set_error(thp, ETOPO_FMRI_NVL, err, 162 TOPO_METH_STR2NVL, in)); 163 164 nvlist_free(out); 165 nvlist_free(in); 166 167 return (0); 168 } 169 170 int 171 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) 172 { 173 uint32_t present = 0; 174 char *scheme; 175 nvlist_t *out = NULL; 176 tnode_t *rnode; 177 178 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 179 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 180 TOPO_METH_PRESENT, out)); 181 182 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 183 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 184 TOPO_METH_PRESENT, out)); 185 186 if (topo_method_invoke(rnode, TOPO_METH_PRESENT, 187 TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) { 188 (void) set_error(thp, *err, err, TOPO_METH_PRESENT, out); 189 return (present); 190 } 191 192 (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present); 193 nvlist_free(out); 194 195 return (present); 196 } 197 198 int 199 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) 200 { 201 uint32_t contains; 202 char *scheme; 203 nvlist_t *in = NULL, *out = NULL; 204 tnode_t *rnode; 205 206 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 207 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 208 TOPO_METH_CONTAINS, NULL)); 209 210 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 211 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 212 TOPO_METH_CONTAINS, NULL)); 213 214 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 215 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 216 NULL)); 217 218 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 || 219 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0) 220 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 221 in)); 222 223 if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0) 224 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 225 out)); 226 227 if (topo_method_invoke(rnode, TOPO_METH_CONTAINS, 228 TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) { 229 nvlist_free(out); 230 return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in)); 231 } 232 233 (void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains); 234 nvlist_free(in); 235 nvlist_free(out); 236 237 return (contains); 238 } 239 240 int 241 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) 242 { 243 char *scheme; 244 uint32_t unusable = 0; 245 nvlist_t *out = NULL; 246 tnode_t *rnode; 247 248 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 249 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 250 TOPO_METH_UNUSABLE, out)); 251 252 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 253 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 254 TOPO_METH_UNUSABLE, out)); 255 256 if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE, 257 TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0) 258 return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out)); 259 260 (void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable); 261 nvlist_free(out); 262 263 return (unusable); 264 } 265 266 int 267 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) 268 { 269 char *scheme; 270 nvlist_t *out = NULL; 271 tnode_t *rnode; 272 273 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 274 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 275 TOPO_METH_EXPAND, out)); 276 277 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 278 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 279 TOPO_METH_EXPAND, out)); 280 281 if (topo_method_invoke(rnode, TOPO_METH_EXPAND, 282 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) 283 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); 284 285 return (0); 286 } 287 288 static int 289 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 290 const char *pname, nvlist_t *args, nvlist_t **prop, 291 int *err) 292 { 293 int rv; 294 nvlist_t *in = NULL; 295 tnode_t *rnode; 296 char *scheme; 297 298 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 299 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 300 TOPO_METH_PROP_GET, in)); 301 302 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 303 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 304 TOPO_METH_PROP_GET, in)); 305 306 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 307 return (set_error(thp, ETOPO_FMRI_NVL, err, 308 TOPO_METH_PROP_GET, in)); 309 310 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 311 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 312 rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname); 313 if (args != NULL) 314 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 315 if (rv != 0) 316 return (set_error(thp, ETOPO_FMRI_NVL, err, 317 TOPO_METH_PROP_GET, in)); 318 319 *prop = NULL; 320 rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET, 321 TOPO_METH_PROP_GET_VERSION, in, prop, err); 322 323 nvlist_free(in); 324 325 if (rv != 0) 326 return (-1); /* *err is set for us */ 327 328 if (*prop == NULL) 329 return (set_error(thp, ETOPO_PROP_NOENT, err, 330 TOPO_METH_PROP_GET, NULL)); 331 return (0); 332 } 333 334 int 335 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 336 { 337 nvlist_t *ap, *prop = NULL; 338 339 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, 340 nvl, &prop, err) < 0) 341 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 342 343 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0) 344 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru", 345 prop)); 346 347 if (topo_hdl_nvdup(thp, ap, asru) < 0) 348 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru", 349 prop)); 350 351 nvlist_free(prop); 352 353 return (0); 354 } 355 356 int 357 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err) 358 { 359 nvlist_t *fp, *prop = NULL; 360 361 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, 362 nvl, &prop, err) < 0) 363 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 364 365 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0) 366 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru", 367 prop)); 368 369 if (topo_hdl_nvdup(thp, fp, fru) < 0) 370 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru", 371 prop)); 372 373 nvlist_free(prop); 374 375 return (0); 376 } 377 378 int 379 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err) 380 { 381 nvlist_t *prop = NULL; 382 char *lp; 383 384 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, 385 NULL, &prop, err) < 0) 386 return (set_error(thp, *err, err, "topo_fmri_label", NULL)); 387 388 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0) 389 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 390 prop)); 391 392 if ((*label = topo_hdl_strdup(thp, lp)) == NULL) 393 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label", 394 prop)); 395 396 nvlist_free(prop); 397 398 return (0); 399 } 400 401 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 402 const char *pname, nvlist_t *args, nvlist_t **prop, 403 int *err) 404 { 405 *prop = NULL; 406 407 return (fmri_prop(thp, nvl, pg, pname, args, prop, err)); 408 } 409 410 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 411 nvlist_t *prop, int flag, nvlist_t *args, int *err) 412 { 413 int rv; 414 nvlist_t *in = NULL, *out = NULL; 415 tnode_t *rnode; 416 char *scheme; 417 418 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 419 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 420 TOPO_METH_PROP_SET, in)); 421 422 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 423 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 424 TOPO_METH_PROP_SET, in)); 425 426 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 427 return (set_error(thp, ETOPO_FMRI_NVL, err, 428 TOPO_METH_PROP_SET, in)); 429 430 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl); 431 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg); 432 rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop); 433 rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag); 434 if (args != NULL) 435 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 436 if (rv != 0) 437 return (set_error(thp, ETOPO_FMRI_NVL, err, 438 TOPO_METH_PROP_SET, in)); 439 440 rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET, 441 TOPO_METH_PROP_SET_VERSION, in, &out, err); 442 443 nvlist_free(in); 444 445 /* no return values */ 446 if (out != NULL) 447 nvlist_free(out); 448 449 if (rv) 450 return (-1); 451 452 return (0); 453 454 } 455 456 int 457 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 458 nvlist_t **pgroup, int *err) 459 { 460 int rv; 461 nvlist_t *in = NULL; 462 tnode_t *rnode; 463 char *scheme; 464 465 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 466 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 467 TOPO_METH_PROP_GET, in)); 468 469 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 470 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 471 TOPO_METH_PROP_GET, in)); 472 473 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 474 return (set_error(thp, ETOPO_FMRI_NVL, err, 475 TOPO_METH_PROP_GET, in)); 476 477 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 478 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 479 if (rv != 0) 480 return (set_error(thp, ETOPO_FMRI_NVL, err, 481 TOPO_METH_PROP_GET, in)); 482 483 *pgroup = NULL; 484 rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET, 485 TOPO_METH_PGRP_GET_VERSION, in, pgroup, err); 486 487 nvlist_free(in); 488 489 if (rv != 0) 490 return (-1); /* *err is set for us */ 491 492 if (*pgroup == NULL) 493 return (set_error(thp, ETOPO_PROP_NOENT, err, 494 TOPO_METH_PROP_GET, NULL)); 495 return (0); 496 } 497 498 int 499 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 500 { 501 uint32_t compare; 502 char *scheme1, *scheme2; 503 nvlist_t *in; 504 nvlist_t *out = NULL; 505 tnode_t *rnode; 506 507 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 508 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 509 TOPO_METH_COMPARE, NULL)); 510 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 511 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 512 TOPO_METH_COMPARE, NULL)); 513 514 if (strcmp(scheme1, scheme2) != 0) 515 return (0); 516 517 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 518 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 519 TOPO_METH_COMPARE, NULL)); 520 521 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 522 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 523 NULL)); 524 525 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 || 526 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0) 527 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 528 in)); 529 530 if (topo_method_invoke(rnode, TOPO_METH_COMPARE, 531 TOPO_METH_COMPARE_VERSION, in, &out, err) < 0) 532 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 533 534 (void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare); 535 nvlist_free(out); 536 nvlist_free(in); 537 538 return (compare); 539 } 540 541 /* 542 * topo_fmri_create 543 * 544 * If possible, creates an FMRI of the requested version in the 545 * requested scheme. Args are passed as part of the inputs to the 546 * fmri-create method of the scheme. 547 */ 548 nvlist_t * 549 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 550 topo_instance_t inst, nvlist_t *nvl, int *err) 551 { 552 nvlist_t *ins; 553 nvlist_t *out; 554 tnode_t *rnode; 555 556 ins = out = NULL; 557 558 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 559 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 560 TOPO_METH_FMRI, NULL)); 561 562 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 563 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 564 TOPO_METH_FMRI, NULL)); 565 566 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 567 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 568 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 569 TOPO_METH_FMRI, ins)); 570 } 571 572 if (nvl != NULL && 573 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 574 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 575 TOPO_METH_FMRI, ins)); 576 } 577 if (topo_method_invoke(rnode, 578 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 579 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 580 } 581 nvlist_free(ins); 582 return (out); 583 } 584