1 /* 2 * 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <ctype.h> 35 #include <alloca.h> 36 #include <limits.h> 37 #include <fm/topo_mod.h> 38 #include <sys/param.h> 39 #include <sys/systeminfo.h> 40 #include <sys/fm/protocol.h> 41 #include <topo_parse.h> 42 #include <topo_subr.h> 43 44 #include <hc_canon.h> 45 46 #define HC "hc" 47 #define HC_VERSION TOPO_VERSION 48 49 static int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 50 topo_instance_t, void *); 51 static void hc_release(topo_mod_t *, tnode_t *); 52 static int hc_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 53 nvlist_t **); 54 static int hc_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 55 nvlist_t **); 56 static int hc_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 57 nvlist_t **); 58 static int hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 59 nvlist_t *, nvlist_t **); 60 static int hc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, 61 nvlist_t *, nvlist_t **); 62 static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 63 nvlist_t **); 64 static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, 65 nvlist_t *, nvlist_t **); 66 67 static nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *, 68 topo_instance_t inst, const nvlist_t *, const char *, const char *, 69 const char *); 70 71 const topo_method_t hc_methods[] = { 72 { "hc_contains", "Hardware Component Contains", HC_VERSION, 73 TOPO_STABILITY_INTERNAL, hc_contains }, 74 { "hc_present", "Hardware Component Present", HC_VERSION, 75 TOPO_STABILITY_INTERNAL, hc_present }, 76 { "hc_unusable", "Hardware Component Unusable", HC_VERSION, 77 TOPO_STABILITY_INTERNAL, hc_unusable }, 78 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 79 TOPO_STABILITY_INTERNAL, hc_fmri_nvl2str }, 80 { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 81 TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl }, 82 { TOPO_METH_COMPARE, TOPO_METH_COMPARE_DESC, TOPO_METH_COMPARE_VERSION, 83 TOPO_STABILITY_INTERNAL, hc_compare }, 84 { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, 85 TOPO_STABILITY_INTERNAL, hc_fmri_create_meth }, 86 { NULL } 87 }; 88 89 const topo_modinfo_t hc_info = 90 { HC, HC_VERSION, hc_enum, hc_release }; 91 92 void 93 hc_init(topo_mod_t *mp) 94 { 95 /* 96 * Turn on module debugging output 97 */ 98 topo_mod_setdebug(mp, TOPO_DBG_ALL); 99 topo_mod_dprintf(mp, "initializing hc builtin\n"); 100 101 if (topo_mod_register(mp, &hc_info, NULL) != 0) { 102 topo_mod_dprintf(mp, "failed to register hc: " 103 "%s\n", topo_mod_errmsg(mp)); 104 } 105 } 106 107 void 108 hc_fini(topo_mod_t *mp) 109 { 110 topo_mod_unregister(mp); 111 } 112 113 /*ARGSUSED*/ 114 int 115 hc_enum(topo_mod_t *mp, tnode_t *pnode, const char *name, topo_instance_t min, 116 topo_instance_t max, void *notused) 117 { 118 nvlist_t *pfmri = NULL; 119 nvlist_t *nvl; 120 int err; 121 /* 122 * Register root node methods 123 */ 124 if (strcmp(name, HC) == 0) { 125 (void) topo_method_register(mp, pnode, hc_methods); 126 return (0); 127 } 128 if (min != max) { 129 topo_mod_dprintf(mp, 130 "Request to enumerate %s component with an " 131 "ambiguous instance number, min (%d) != max (%d).\n", 132 HC, min, max); 133 return (topo_mod_seterrno(mp, EINVAL)); 134 } 135 136 (void) topo_node_resource(pnode, &pfmri, &err); 137 nvl = hc_fmri_create(mp, pfmri, FM_HC_SCHEME_VERSION, name, min, 138 NULL, NULL, NULL, NULL); 139 nvlist_free(pfmri); /* callee ignores NULLs */ 140 if (nvl == NULL) 141 return (-1); 142 143 if (topo_node_bind(mp, pnode, name, min, nvl, NULL) == NULL) { 144 topo_mod_dprintf(mp, "topo_node_bind failed: %s\n", 145 topo_strerror(topo_mod_errno(mp))); 146 nvlist_free(nvl); 147 return (-1); 148 } 149 nvlist_free(nvl); 150 return (0); 151 } 152 153 /*ARGSUSED*/ 154 static void 155 hc_release(topo_mod_t *mp, tnode_t *node) 156 { 157 topo_method_unregister_all(mp, node); 158 } 159 160 /*ARGSUSED*/ 161 static int 162 hc_contains(topo_mod_t *mp, tnode_t *node, topo_version_t version, 163 nvlist_t *in, nvlist_t **out) 164 { 165 return (topo_mod_seterrno(mp, EMOD_METHOD_NOTSUP)); 166 } 167 168 /*ARGSUSED*/ 169 static int 170 hc_present(topo_mod_t *mp, tnode_t *node, topo_version_t version, 171 nvlist_t *in, nvlist_t **out) 172 { 173 return (topo_mod_seterrno(mp, EMOD_METHOD_NOTSUP)); 174 } 175 176 /*ARGSUSED*/ 177 static int 178 hc_unusable(topo_mod_t *mp, tnode_t *node, topo_version_t version, 179 nvlist_t *in, nvlist_t **out) 180 { 181 return (topo_mod_seterrno(mp, EMOD_METHOD_NOTSUP)); 182 } 183 184 /*ARGSUSED*/ 185 static int 186 hc_compare(topo_mod_t *mp, tnode_t *node, topo_version_t version, 187 nvlist_t *in, nvlist_t **out) 188 { 189 uint8_t v1, v2; 190 nvlist_t *nv1, *nv2; 191 nvlist_t **hcp1, **hcp2; 192 int err, i; 193 uint_t nhcp1, nhcp2; 194 195 if (version > TOPO_METH_COMPARE_VERSION) 196 return (topo_mod_seterrno(mp, EMOD_VER_NEW)); 197 198 if (nvlist_lookup_nvlist(in, "nv1", &nv1) != 0 || 199 nvlist_lookup_nvlist(in, "nv2", &nv2) != 0) 200 return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); 201 202 if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 || 203 nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 || 204 v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION) 205 return (topo_mod_seterrno(mp, EMOD_FMRI_VERSION)); 206 207 err = nvlist_lookup_nvlist_array(nv1, FM_FMRI_HC_LIST, &hcp1, &nhcp1); 208 err |= nvlist_lookup_nvlist_array(nv2, FM_FMRI_HC_LIST, &hcp2, &nhcp2); 209 if (err != 0) 210 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 211 212 if (nhcp1 != nhcp2) 213 return (0); 214 215 for (i = 0; i < nhcp1; i++) { 216 char *nm1 = NULL; 217 char *nm2 = NULL; 218 char *id1 = NULL; 219 char *id2 = NULL; 220 221 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_NAME, &nm1); 222 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_NAME, &nm2); 223 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_ID, &id1); 224 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_ID, &id2); 225 if (nm1 == NULL || nm2 == NULL || id1 == NULL || id2 == NULL) 226 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 227 228 if (strcmp(nm1, nm2) == 0 && strcmp(id1, id2) == 0) 229 continue; 230 231 return (0); 232 } 233 234 return (1); 235 } 236 237 static ssize_t 238 fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 239 { 240 nvlist_t **hcprs = NULL; 241 nvlist_t *anvl = NULL; 242 uint8_t version; 243 ssize_t size = 0; 244 uint_t hcnprs; 245 char *achas = NULL; 246 char *adom = NULL; 247 char *aprod = NULL; 248 char *asrvr = NULL; 249 char *ahost = NULL; 250 char *serial = NULL; 251 char *part = NULL; 252 char *root = NULL; 253 char *rev = NULL; 254 int more_auth = 0; 255 int err, i; 256 257 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 258 version > FM_HC_SCHEME_VERSION) 259 return (-1); 260 261 /* Get authority, if present */ 262 err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); 263 if (err != 0 && err != ENOENT) 264 return (-1); 265 266 if ((err = nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root)) != 0) 267 return (-1); 268 269 err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs); 270 if (err != 0 || hcprs == NULL) 271 return (-1); 272 273 if (anvl != NULL) { 274 (void) nvlist_lookup_string(anvl, 275 FM_FMRI_AUTH_PRODUCT, &aprod); 276 (void) nvlist_lookup_string(anvl, 277 FM_FMRI_AUTH_CHASSIS, &achas); 278 (void) nvlist_lookup_string(anvl, 279 FM_FMRI_AUTH_DOMAIN, &adom); 280 (void) nvlist_lookup_string(anvl, 281 FM_FMRI_AUTH_SERVER, &asrvr); 282 (void) nvlist_lookup_string(anvl, 283 FM_FMRI_AUTH_HOST, &ahost); 284 if (aprod != NULL) 285 more_auth++; 286 if (achas != NULL) 287 more_auth++; 288 if (adom != NULL) 289 more_auth++; 290 if (asrvr != NULL) 291 more_auth++; 292 if (ahost != NULL) 293 more_auth++; 294 } 295 296 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial); 297 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part); 298 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev); 299 300 /* hc:// */ 301 topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://"); 302 303 /* authority, if any */ 304 if (aprod != NULL) 305 topo_fmristr_build(&size, 306 buf, buflen, aprod, FM_FMRI_AUTH_PRODUCT "=", 307 --more_auth > 0 ? "," : NULL); 308 if (achas != NULL) 309 topo_fmristr_build(&size, 310 buf, buflen, achas, FM_FMRI_AUTH_CHASSIS "=", 311 --more_auth > 0 ? "," : NULL); 312 if (adom != NULL) 313 topo_fmristr_build(&size, 314 buf, buflen, adom, FM_FMRI_AUTH_DOMAIN "=", 315 --more_auth > 0 ? "," : NULL); 316 if (asrvr != NULL) 317 topo_fmristr_build(&size, 318 buf, buflen, asrvr, FM_FMRI_AUTH_SERVER "=", 319 --more_auth > 0 ? "," : NULL); 320 if (ahost != NULL) 321 topo_fmristr_build(&size, 322 buf, buflen, ahost, FM_FMRI_AUTH_HOST "=", 323 NULL); 324 325 /* separating slash */ 326 if (serial != NULL || part != NULL || rev != NULL) 327 topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL); 328 329 /* hardware-id part */ 330 topo_fmristr_build(&size, 331 buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", NULL); 332 topo_fmristr_build(&size, 333 buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL); 334 topo_fmristr_build(&size, 335 buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL); 336 337 /* separating slash */ 338 topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL); 339 340 /* hc-root */ 341 topo_fmristr_build(&size, buf, buflen, root, NULL, NULL); 342 343 /* all the pairs */ 344 for (i = 0; i < hcnprs; i++) { 345 char *nm = NULL; 346 char *id = NULL; 347 348 if (i > 0) 349 topo_fmristr_build(&size, 350 buf, buflen, "/", NULL, NULL); 351 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm); 352 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id); 353 if (nm == NULL || id == NULL) 354 return (0); 355 topo_fmristr_build(&size, buf, buflen, nm, NULL, "="); 356 topo_fmristr_build(&size, buf, buflen, id, NULL, NULL); 357 } 358 359 return (size); 360 } 361 362 /*ARGSUSED*/ 363 static int 364 hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 365 nvlist_t *nvl, nvlist_t **out) 366 { 367 ssize_t len; 368 char *name = NULL; 369 nvlist_t *fmristr; 370 371 if (version > TOPO_METH_NVL2STR_VERSION) 372 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 373 374 if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 || 375 (name = topo_mod_alloc(mod, len + 1)) == NULL || 376 fmri_nvl2str(nvl, name, len + 1) == 0) { 377 if (name != NULL) 378 topo_mod_free(mod, name, len + 1); 379 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 380 } 381 382 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) 383 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 384 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 385 topo_mod_free(mod, name, len + 1); 386 nvlist_free(fmristr); 387 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 388 } 389 topo_mod_free(mod, name, len + 1); 390 *out = fmristr; 391 392 return (0); 393 } 394 395 static nvlist_t * 396 hc_base_fmri_create(topo_mod_t *mod, const nvlist_t *auth, const char *part, 397 const char *rev, const char *serial) 398 { 399 nvlist_t *fmri; 400 int err = 0; 401 402 /* 403 * Create base HC nvlist 404 */ 405 if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 406 return (NULL); 407 408 err = nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION); 409 err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC); 410 err |= nvlist_add_string(fmri, FM_FMRI_HC_ROOT, ""); 411 if (err != 0) { 412 nvlist_free(fmri); 413 return (NULL); 414 } 415 416 /* 417 * Add optional payload members 418 */ 419 if (serial != NULL) 420 (void) nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID, serial); 421 if (part != NULL) 422 (void) nvlist_add_string(fmri, FM_FMRI_HC_PART, part); 423 if (rev != NULL) 424 (void) nvlist_add_string(fmri, FM_FMRI_HC_REVISION, rev); 425 if (auth != NULL) 426 (void) nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, 427 (nvlist_t *)auth); 428 429 return (fmri); 430 } 431 432 static nvlist_t ** 433 make_hc_pairs(topo_mod_t *mod, char *fromstr, int *num) 434 { 435 nvlist_t **pa; 436 char *starti, *startn, *endi, *endi2; 437 char *ne, *ns; 438 char *cname; 439 char *find; 440 char *cid; 441 int nslashes = 0; 442 int npairs = 0; 443 int i, e; 444 445 /* 446 * Count equal signs and slashes to determine how many 447 * hc-pairs will be present in the final FMRI. There should 448 * be at least as many slashes as equal signs. There can be 449 * more, though if the string after an = includes them. 450 */ 451 find = fromstr; 452 while ((ne = strchr(find, '=')) != NULL) { 453 find = ne + 1; 454 npairs++; 455 } 456 457 find = fromstr; 458 while ((ns = strchr(find, '/')) != NULL) { 459 find = ns + 1; 460 nslashes++; 461 } 462 463 /* 464 * Do we appear to have a well-formed string version of the FMRI? 465 */ 466 if (nslashes < npairs || npairs == 0) 467 return (NULL); 468 469 *num = npairs; 470 471 find = fromstr; 472 473 pa = topo_mod_alloc(mod, npairs * sizeof (nvlist_t *)); 474 /* 475 * We go through a pretty complicated procedure to find the 476 * name and id for each pair. That's because, unfortunately, 477 * we have some ids that can have slashes within them. So 478 * we can't just search for the next slash after the equal sign 479 * and decide that starts a new pair. Instead we have to find 480 * an equal sign for the next pair and work our way back to the 481 * slash from there. 482 */ 483 for (i = 0; i < npairs; i++) { 484 pa[i] = NULL; 485 startn = strchr(find, '/'); 486 if (startn == NULL) 487 break; 488 startn++; 489 starti = strchr(find, '='); 490 if (starti == NULL) 491 break; 492 *starti = '\0'; 493 cname = topo_mod_strdup(mod, startn); 494 *starti++ = '='; 495 endi = strchr(starti, '='); 496 if (endi != NULL) { 497 *endi = '\0'; 498 endi2 = strrchr(starti, '/'); 499 if (endi2 == NULL) 500 break; 501 *endi = '='; 502 *endi2 = '\0'; 503 cid = topo_mod_strdup(mod, starti); 504 *endi2 = '/'; 505 find = endi2; 506 } else { 507 cid = topo_mod_strdup(mod, starti); 508 find = starti + strlen(starti); 509 } 510 if ((e = topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME)) != 0) { 511 topo_mod_strfree(mod, cname); 512 topo_mod_strfree(mod, cid); 513 break; 514 } 515 516 e = nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname); 517 e |= nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid); 518 519 topo_mod_strfree(mod, cname); 520 topo_mod_strfree(mod, cid); 521 522 if (e != 0) { 523 break; 524 } 525 } 526 if (i < npairs) { 527 while (i >= 0) 528 if (pa[i--] != NULL) 529 nvlist_free(pa[i + 1]); 530 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 531 return (NULL); 532 } 533 534 return (pa); 535 } 536 537 /*ARGSUSED*/ 538 static int 539 hc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 540 nvlist_t *in, nvlist_t **out) 541 { 542 nvlist_t **pa = NULL; 543 nvlist_t *nf = NULL; 544 char *str, *copy; 545 int npairs; 546 int i, e; 547 548 if (version > TOPO_METH_STR2NVL_VERSION) 549 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 550 551 if (nvlist_lookup_string(in, "fmri-string", &str) != 0) 552 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 553 554 /* We're expecting a string version of an hc scheme FMRI */ 555 if (strncmp(str, "hc:///", 6) != 0) 556 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 557 558 copy = topo_mod_strdup(mod, str + 5); 559 if ((pa = make_hc_pairs(mod, copy, &npairs)) == NULL) { 560 topo_mod_strfree(mod, copy); 561 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 562 } 563 topo_mod_strfree(mod, copy); 564 565 if ((nf = hc_base_fmri_create(mod, NULL, NULL, NULL, NULL)) == NULL) 566 goto hcfmbail; 567 if ((e = nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, npairs)) == 0) 568 e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, npairs); 569 if (e != 0) { 570 topo_mod_dprintf(mod, "construction of new hc nvl failed"); 571 goto hcfmbail; 572 } 573 for (i = 0; i < npairs; i++) 574 nvlist_free(pa[i]); 575 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 576 *out = nf; 577 578 return (0); 579 580 hcfmbail: 581 if (nf != NULL) 582 nvlist_free(nf); 583 for (i = 0; i < npairs; i++) 584 nvlist_free(pa[i]); 585 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 586 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 587 } 588 589 static nvlist_t * 590 hc_list_create(topo_mod_t *mod, const char *name, char *inst) 591 { 592 int err; 593 nvlist_t *hc; 594 595 if (topo_mod_nvalloc(mod, &hc, NV_UNIQUE_NAME) != 0) 596 return (NULL); 597 598 err = nvlist_add_string(hc, FM_FMRI_HC_NAME, name); 599 err |= nvlist_add_string(hc, FM_FMRI_HC_ID, inst); 600 if (err != 0) { 601 nvlist_free(hc); 602 return (NULL); 603 } 604 605 return (hc); 606 } 607 608 static nvlist_t * 609 hc_create_seterror(topo_mod_t *mod, nvlist_t **hcl, int n, nvlist_t *fmri, 610 int err) 611 { 612 int i; 613 614 if (hcl != NULL) { 615 for (i = 0; i < n + 1; ++i) 616 nvlist_free(hcl[i]); 617 618 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (n + 1)); 619 } 620 621 nvlist_free(fmri); 622 623 (void) topo_mod_seterrno(mod, err); 624 625 topo_mod_dprintf(mod, "unable to create hc FMRI: %s\n", 626 topo_mod_errmsg(mod)); 627 628 return (NULL); 629 } 630 631 static int 632 hc_name_canonical(const char *name) 633 { 634 int i; 635 /* 636 * Only enumerate elements with correct canonical names 637 */ 638 for (i = 0; i < Hc_ncanon; i++) { 639 if (strcmp(name, Hc_canon[i]) == 0) 640 break; 641 } 642 if (i >= Hc_ncanon) 643 return (0); 644 else 645 return (1); 646 } 647 648 static nvlist_t * 649 hc_fmri_create(topo_mod_t *mod, nvlist_t *pfmri, int version, const char *name, 650 topo_instance_t inst, const nvlist_t *auth, const char *part, 651 const char *rev, const char *serial) 652 { 653 int i; 654 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 655 uint_t pelems = 0; 656 nvlist_t **phcl = NULL; 657 nvlist_t **hcl = NULL; 658 nvlist_t *fmri = NULL; 659 660 if (version > FM_HC_SCHEME_VERSION) 661 return (hc_create_seterror(mod, 662 hcl, pelems, fmri, EMOD_VER_OLD)); 663 else if (version < FM_HC_SCHEME_VERSION) 664 return (hc_create_seterror(mod, 665 hcl, pelems, fmri, EMOD_VER_NEW)); 666 667 /* 668 * Check that the requested name is in our canonical list 669 */ 670 if (hc_name_canonical(name) == 0) 671 return (hc_create_seterror(mod, 672 hcl, pelems, fmri, EMOD_NONCANON)); 673 /* 674 * Copy the parent's HC_LIST 675 */ 676 if (pfmri != NULL) { 677 if (nvlist_lookup_nvlist_array(pfmri, FM_FMRI_HC_LIST, 678 &phcl, &pelems) != 0) 679 return (hc_create_seterror(mod, 680 hcl, pelems, fmri, EMOD_FMRI_MALFORM)); 681 } 682 683 hcl = topo_mod_zalloc(mod, sizeof (nvlist_t *) * (pelems + 1)); 684 if (hcl == NULL) 685 return (hc_create_seterror(mod, hcl, pelems, fmri, 686 EMOD_NOMEM)); 687 688 for (i = 0; i < pelems; ++i) 689 if (topo_mod_nvdup(mod, phcl[i], &hcl[i]) != 0) 690 return (hc_create_seterror(mod, 691 hcl, pelems, fmri, EMOD_FMRI_NVL)); 692 693 (void) snprintf(str, sizeof (str), "%d", inst); 694 if ((hcl[i] = hc_list_create(mod, name, str)) == NULL) 695 return (hc_create_seterror(mod, 696 hcl, pelems, fmri, EMOD_FMRI_NVL)); 697 698 if ((fmri = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL) 699 return (hc_create_seterror(mod, 700 hcl, pelems, fmri, EMOD_FMRI_NVL)); 701 702 if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, hcl, pelems + 1) 703 != 0) 704 return (hc_create_seterror(mod, 705 hcl, pelems, fmri, EMOD_FMRI_NVL)); 706 707 if (hcl != NULL) { 708 for (i = 0; i < pelems + 1; ++i) { 709 if (hcl[i] != NULL) 710 nvlist_free(hcl[i]); 711 } 712 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (pelems + 1)); 713 } 714 715 return (fmri); 716 } 717 718 /*ARGSUSED*/ 719 static int 720 hc_fmri_create_meth(topo_mod_t *mp, tnode_t *node, topo_version_t version, 721 nvlist_t *in, nvlist_t **out) 722 { 723 int ret; 724 nvlist_t *args, *pfmri = NULL; 725 nvlist_t *auth; 726 uint32_t inst; 727 char *name, *serial, *rev, *part; 728 729 if (version > TOPO_METH_FMRI_VERSION) 730 return (topo_mod_seterrno(mp, EMOD_VER_NEW)); 731 732 /* First the must-have fields */ 733 if (nvlist_lookup_string(in, TOPO_METH_FMRI_ARG_NAME, &name) != 0) 734 return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); 735 if (nvlist_lookup_uint32(in, TOPO_METH_FMRI_ARG_INST, &inst) != 0) 736 return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); 737 738 /* 739 * args is optional 740 */ 741 pfmri = NULL; 742 auth = NULL; 743 serial = rev = part = NULL; 744 if ((ret = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args)) 745 != 0) { 746 if (ret != ENOENT) 747 return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); 748 } else { 749 750 /* And then optional arguments */ 751 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, 752 &pfmri); 753 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, 754 &auth); 755 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_PART, 756 &part); 757 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_REV, &rev); 758 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_SER, 759 &serial); 760 } 761 762 *out = hc_fmri_create(mp, 763 pfmri, version, name, inst, auth, part, rev, serial); 764 if (*out == NULL) 765 return (-1); 766 return (0); 767 } 768