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 rsrc { 278 int rs_err; 279 int rs_flag; 280 nvlist_t **rs_fprop; 281 nvlist_t *rs_priv; 282 }; 283 284 /*ARGSUSED*/ 285 static int 286 get_prop(topo_hdl_t *thp, tnode_t *node, void *pdata) 287 { 288 struct rsrc *rsp = (struct rsrc *)pdata; 289 290 if (rsp->rs_flag == 0) { 291 if (topo_node_asru(node, rsp->rs_fprop, rsp->rs_priv, 292 &rsp->rs_err) < 0) 293 return (-1); 294 295 return (0); 296 } else { 297 if (topo_node_fru(node, rsp->rs_fprop, rsp->rs_priv, 298 &rsp->rs_err) < 0) 299 return (-1); 300 301 return (0); 302 } 303 } 304 305 int 306 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 307 { 308 struct rsrc r; 309 310 r.rs_flag = 0; 311 r.rs_err = 0; 312 r.rs_priv = nvl; 313 r.rs_fprop = asru; 314 if (topo_fmri_invoke(thp, nvl, get_prop, &r, err) < 0) { 315 316 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 317 } 318 319 return (0); 320 } 321 322 int 323 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, 324 int *err) 325 { 326 struct rsrc r; 327 328 r.rs_flag = 1; 329 r.rs_err = 0; 330 r.rs_priv = nvl; 331 r.rs_fprop = fru; 332 if (topo_fmri_invoke(thp, nvl, get_prop, &r, err) < 0) { 333 334 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 335 } 336 337 return (0); 338 } 339 340 int 341 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 342 { 343 int rc; 344 char *scheme1, *scheme2; 345 nvlist_t *in; 346 nvlist_t *out = NULL; 347 tnode_t *rnode; 348 349 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 350 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 351 TOPO_METH_COMPARE, NULL)); 352 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 353 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 354 TOPO_METH_COMPARE, NULL)); 355 356 if (strcmp(scheme1, scheme2) != 0) 357 return (0); 358 359 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 360 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 361 TOPO_METH_COMPARE, NULL)); 362 363 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 364 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 365 NULL)); 366 367 if (nvlist_add_nvlist(in, "nv1", f1) != 0 || 368 nvlist_add_nvlist(in, "nv2", f2) != 0) 369 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 370 in)); 371 372 if ((rc = topo_method_invoke(rnode, TOPO_METH_COMPARE, 373 TOPO_METH_COMPARE_VERSION, in, &out, err)) < 0) 374 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 375 376 nvlist_free(in); 377 378 return (rc); 379 } 380 381 struct topo_lookup { 382 nvlist_t *tl_resource; 383 topo_walk_cb_t tl_func; 384 int tl_ret; 385 void *tl_pdata; 386 }; 387 388 static int 389 walk_lookup(topo_hdl_t *thp, tnode_t *node, void *pdata) 390 { 391 int rc; 392 struct topo_lookup *tlp = (struct topo_lookup *)pdata; 393 nvlist_t *r1, *r2 = tlp->tl_resource; 394 395 if (topo_node_resource(node, &r1, &tlp->tl_ret) != 0) 396 return (TOPO_WALK_ERR); 397 398 rc = topo_fmri_compare(thp, r1, r2, &tlp->tl_ret); 399 nvlist_free(r1); 400 if (rc == 0) 401 return (TOPO_WALK_NEXT); 402 else if (rc == -1) 403 return (TOPO_WALK_ERR); 404 405 tlp->tl_ret = tlp->tl_func(thp, node, tlp->tl_pdata); 406 407 return (TOPO_WALK_TERMINATE); 408 } 409 410 int 411 topo_fmri_invoke(topo_hdl_t *thp, nvlist_t *nvl, topo_walk_cb_t cb_f, 412 void *pdata, int *ret) 413 { 414 int err; 415 topo_walk_t *wp; 416 char *scheme; 417 struct topo_lookup tl; 418 419 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 420 return (set_error(thp, ETOPO_METHOD_INVAL, ret, 421 "topo_fmri_invoke", NULL)); 422 423 tl.tl_resource = nvl; 424 tl.tl_func = cb_f; 425 tl.tl_pdata = pdata; 426 tl.tl_ret = 0; 427 if ((wp = topo_walk_init(thp, scheme, walk_lookup, &tl, &err)) == NULL) 428 return (set_error(thp, err, ret, "topo_fmri_invoke", NULL)); 429 430 err = topo_walk_step(wp, TOPO_WALK_CHILD); 431 topo_walk_fini(wp); 432 433 if (err == TOPO_WALK_ERR) { 434 *ret = err; 435 return (-1); 436 } 437 438 *ret = tl.tl_ret; 439 440 return (0); 441 } 442 443 /* 444 * topo_fmri_create 445 * 446 * If possible, creates an FMRI of the requested version in the 447 * requested scheme. Args are passed as part of the inputs to the 448 * fmri-create method of the scheme. 449 */ 450 nvlist_t * 451 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 452 topo_instance_t inst, nvlist_t *nvl, int *err) 453 { 454 nvlist_t *ins; 455 nvlist_t *out; 456 tnode_t *rnode; 457 458 ins = out = NULL; 459 460 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 461 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 462 TOPO_METH_FMRI, NULL)); 463 464 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 465 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 466 TOPO_METH_FMRI, NULL)); 467 468 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 469 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 470 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 471 TOPO_METH_FMRI, ins)); 472 } 473 474 if (nvl != NULL && 475 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 476 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 477 TOPO_METH_FMRI, ins)); 478 } 479 if (topo_method_invoke(rnode, 480 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 481 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 482 } 483 nvlist_free(ins); 484 return (out); 485 } 486