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_subr.h> 36 #include <topo_string.h> 37 38 /*ARGSUSED*/ 39 static int 40 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 41 { 42 if (nvlp != NULL) 43 nvlist_free(nvlp); 44 45 topo_dprintf(TOPO_DBG_ERR, "%s failed: %s\n", method, 46 topo_strerror(err)); 47 48 *errp = err; 49 return (-1); 50 } 51 52 /*ARGSUSED*/ 53 static nvlist_t * 54 set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 55 { 56 if (nvlp != NULL) 57 nvlist_free(nvlp); 58 59 topo_dprintf(TOPO_DBG_ERR, "%s failed: %s\n", method, 60 topo_strerror(err)); 61 62 *errp = err; 63 return (NULL); 64 } 65 66 int 67 topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err) 68 { 69 char *scheme, *str; 70 nvlist_t *out = NULL; 71 tnode_t *rnode; 72 73 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 74 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 75 TOPO_METH_NVL2STR, out)); 76 77 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 78 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 79 TOPO_METH_NVL2STR, out)); 80 81 if (topo_method_invoke(rnode, TOPO_METH_NVL2STR, 82 TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0) 83 return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out)); 84 85 if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0) 86 return (set_error(thp, ETOPO_METHOD_INVAL, err, 87 TOPO_METH_NVL2STR, out)); 88 89 if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL) 90 return (set_error(thp, ETOPO_NOMEM, err, 91 TOPO_METH_NVL2STR, out)); 92 93 nvlist_free(out); 94 95 return (0); 96 } 97 98 int 99 topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri, 100 int *err) 101 { 102 char *f, scheme[PATH_MAX]; 103 nvlist_t *out = NULL, *in = NULL; 104 tnode_t *rnode; 105 106 (void) strlcpy(scheme, fmristr, sizeof (scheme)); 107 if ((f = strrchr(scheme, ':')) == NULL) 108 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 109 TOPO_METH_STR2NVL, in)); 110 111 *f = '\0'; /* strip trailing FMRI path */ 112 113 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 114 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 115 TOPO_METH_STR2NVL, in)); 116 117 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 118 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 119 in)); 120 121 if (nvlist_add_string(in, "fmri-string", fmristr) != 0) 122 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 123 in)); 124 125 if (topo_method_invoke(rnode, TOPO_METH_STR2NVL, 126 TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0) 127 return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in)); 128 129 if (out == NULL || 130 topo_hdl_nvdup(thp, out, fmri) != 0) 131 return (set_error(thp, ETOPO_FMRI_NVL, err, 132 TOPO_METH_STR2NVL, in)); 133 134 nvlist_free(out); 135 nvlist_free(in); 136 137 return (0); 138 } 139 140 int 141 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) 142 { 143 int rc; 144 char *scheme; 145 nvlist_t *out = NULL; 146 tnode_t *rnode; 147 148 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 149 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 150 TOPO_METH_PRESENT, out)); 151 152 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 153 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 154 TOPO_METH_PRESENT, out)); 155 156 if ((rc = topo_method_invoke(rnode, TOPO_METH_PRESENT, 157 TOPO_METH_PRESENT_VERSION, fmri, &out, err)) < 0) 158 return (set_error(thp, *err, err, TOPO_METH_PRESENT, out)); 159 160 return (rc); 161 } 162 163 int 164 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) 165 { 166 int rc; 167 char *scheme; 168 nvlist_t *in, *out = NULL; 169 tnode_t *rnode; 170 171 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 172 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 173 TOPO_METH_CONTAINS, out)); 174 175 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 176 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 177 TOPO_METH_CONTAINS, out)); 178 179 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 180 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 181 out)); 182 183 if (nvlist_add_nvlist(in, "fmri", fmri) != 0 || 184 nvlist_add_nvlist(in, "subfmri", subfmri) != 0) 185 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 186 out)); 187 188 if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0) 189 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 190 out)); 191 192 if ((rc = topo_method_invoke(rnode, TOPO_METH_CONTAINS, 193 TOPO_METH_CONTAINS_VERSION, fmri, &out, err)) < 0) 194 return (set_error(thp, *err, err, TOPO_METH_CONTAINS, out)); 195 196 return (rc); 197 } 198 199 int 200 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) 201 { 202 int rc; 203 char *scheme; 204 nvlist_t *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_UNUSABLE, out)); 210 211 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 212 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 213 TOPO_METH_UNUSABLE, out)); 214 215 if ((rc = topo_method_invoke(rnode, TOPO_METH_UNUSABLE, 216 TOPO_METH_UNUSABLE_VERSION, fmri, &out, err)) < 0) 217 return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out)); 218 219 return (rc); 220 } 221 222 int 223 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) 224 { 225 char *scheme; 226 nvlist_t *out = NULL; 227 tnode_t *rnode; 228 229 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 230 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 231 TOPO_METH_EXPAND, out)); 232 233 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 234 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 235 TOPO_METH_EXPAND, out)); 236 237 if (topo_method_invoke(rnode, TOPO_METH_EXPAND, 238 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) 239 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); 240 241 return (0); 242 } 243 244 struct rsrc { 245 int rs_err; 246 int rs_flag; 247 nvlist_t **rs_fprop; 248 nvlist_t *rs_priv; 249 }; 250 251 /*ARGSUSED*/ 252 static int 253 get_prop(topo_hdl_t *thp, tnode_t *node, void *pdata) 254 { 255 struct rsrc *rsp = (struct rsrc *)pdata; 256 257 if (rsp->rs_flag == 0) { 258 if (topo_node_asru(node, rsp->rs_fprop, rsp->rs_priv, 259 &rsp->rs_err) < 0) 260 return (-1); 261 262 return (0); 263 } else { 264 if (topo_node_fru(node, rsp->rs_fprop, rsp->rs_priv, 265 &rsp->rs_err) < 0) 266 return (-1); 267 268 return (0); 269 } 270 } 271 272 int 273 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 274 { 275 char *uuid = NULL; 276 struct rsrc r; 277 278 if (thp->th_uuid == NULL) { 279 if ((uuid = topo_snap_hold(thp, NULL, err)) == NULL) 280 return (set_error(thp, *err, err, "topo_fmri_asru", 281 NULL)); 282 } 283 284 r.rs_flag = 0; 285 r.rs_err = 0; 286 r.rs_priv = nvl; 287 r.rs_fprop = asru; 288 if (topo_fmri_invoke(thp, nvl, get_prop, &r, err) < 0) { 289 if (uuid != NULL) { 290 topo_hdl_strfree(thp, uuid); 291 topo_snap_release(thp); 292 } 293 294 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 295 } 296 297 if (uuid != NULL) { 298 topo_hdl_strfree(thp, uuid); 299 topo_snap_release(thp); 300 } 301 302 return (0); 303 } 304 305 int 306 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, 307 int *err) 308 { 309 char *uuid = NULL; 310 struct rsrc r; 311 312 if (thp->th_uuid == NULL) { 313 if ((uuid = topo_snap_hold(thp, NULL, err)) == NULL) 314 return (set_error(thp, *err, err, "topo_fmri_fru", 315 NULL)); 316 } 317 318 r.rs_flag = 1; 319 r.rs_err = 0; 320 r.rs_priv = nvl; 321 r.rs_fprop = fru; 322 if (topo_fmri_invoke(thp, nvl, get_prop, &r, err) < 0) { 323 if (uuid != NULL) { 324 topo_hdl_strfree(thp, uuid); 325 topo_snap_release(thp); 326 } 327 328 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 329 } 330 331 if (uuid != NULL) { 332 topo_hdl_strfree(thp, uuid); 333 topo_snap_release(thp); 334 } 335 336 return (0); 337 } 338 339 int 340 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 341 { 342 int rc; 343 char *scheme1, *scheme2; 344 nvlist_t *in; 345 nvlist_t *out = NULL; 346 tnode_t *rnode; 347 348 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 349 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 350 TOPO_METH_COMPARE, NULL)); 351 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 352 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 353 TOPO_METH_COMPARE, NULL)); 354 355 if (strcmp(scheme1, scheme2) != 0) 356 return (0); 357 358 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 359 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 360 TOPO_METH_COMPARE, NULL)); 361 362 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 363 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 364 NULL)); 365 366 if (nvlist_add_nvlist(in, "nv1", f1) != 0 || 367 nvlist_add_nvlist(in, "nv2", f2) != 0) 368 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 369 in)); 370 371 if ((rc = topo_method_invoke(rnode, TOPO_METH_COMPARE, 372 TOPO_METH_COMPARE_VERSION, in, &out, err)) < 0) 373 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 374 375 nvlist_free(in); 376 377 return (rc); 378 } 379 380 struct topo_lookup { 381 nvlist_t *tl_resource; 382 topo_walk_cb_t tl_func; 383 int tl_err; 384 void *tl_pdata; 385 }; 386 387 static int 388 walk_lookup(topo_hdl_t *thp, tnode_t *node, void *pdata) 389 { 390 int rc; 391 struct topo_lookup *tlp = (struct topo_lookup *)pdata; 392 nvlist_t *r1, *r2 = tlp->tl_resource; 393 394 if (topo_node_resource(node, &r1, &tlp->tl_err) != 0) 395 return (TOPO_WALK_ERR); 396 397 rc = topo_fmri_compare(thp, r1, r2, &tlp->tl_err); 398 nvlist_free(r1); 399 if (rc == 0) 400 return (TOPO_WALK_NEXT); 401 else if (rc == -1) 402 return (TOPO_WALK_ERR); 403 404 tlp->tl_err = tlp->tl_func(thp, node, tlp->tl_pdata); 405 406 return (TOPO_WALK_TERMINATE); 407 } 408 409 int 410 topo_fmri_invoke(topo_hdl_t *thp, nvlist_t *nvl, topo_walk_cb_t cb_f, 411 void *pdata, int *err) 412 { 413 topo_walk_t *wp; 414 char *scheme; 415 struct topo_lookup tl; 416 417 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 418 return (set_error(thp, ETOPO_METHOD_INVAL, err, 419 "topo_fmri_invoke", NULL)); 420 421 tl.tl_resource = nvl; 422 tl.tl_func = cb_f; 423 tl.tl_pdata = pdata; 424 tl.tl_err = 0; 425 if ((wp = topo_walk_init(thp, scheme, walk_lookup, &tl, err)) == NULL) 426 return (set_error(thp, *err, err, "topo_fmri_invoke", NULL)); 427 428 (void) topo_walk_step(wp, TOPO_WALK_CHILD); 429 topo_walk_fini(wp); 430 431 if (tl.tl_err != 0) { 432 *err = tl.tl_err; 433 return (-1); 434 } 435 436 return (0); 437 } 438 439 /* 440 * topo_fmri_create 441 * 442 * If possible, creates an FMRI of the requested version in the 443 * requested scheme. Args are passed as part of the inputs to the 444 * fmri-create method of the scheme. 445 */ 446 nvlist_t * 447 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 448 topo_instance_t inst, nvlist_t *nvl, int *err) 449 { 450 nvlist_t *ins; 451 nvlist_t *out; 452 tnode_t *rnode; 453 454 ins = out = NULL; 455 456 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 457 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 458 TOPO_METH_FMRI, NULL)); 459 460 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 461 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 462 TOPO_METH_FMRI, NULL)); 463 464 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 465 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 466 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 467 TOPO_METH_FMRI, ins)); 468 } 469 470 if (nvl != NULL && 471 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 472 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 473 TOPO_METH_FMRI, ins)); 474 } 475 if (topo_method_invoke(rnode, 476 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 477 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 478 } 479 nvlist_free(ins); 480 return (out); 481 } 482