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 <fm/topo_hc.h> 39 #include <sys/param.h> 40 #include <sys/systeminfo.h> 41 #include <sys/fm/protocol.h> 42 #include <sys/stat.h> 43 #include <sys/systeminfo.h> 44 #include <sys/utsname.h> 45 46 #include <topo_method.h> 47 #include <topo_subr.h> 48 #include <hc.h> 49 50 static int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 51 topo_instance_t, void *, void *); 52 static void hc_release(topo_mod_t *, tnode_t *); 53 static int hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 54 nvlist_t *, nvlist_t **); 55 static int hc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, 56 nvlist_t *, nvlist_t **); 57 static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 58 nvlist_t **); 59 static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, 60 nvlist_t *, nvlist_t **); 61 62 static nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *, 63 topo_instance_t inst, const nvlist_t *, const char *, const char *, 64 const char *); 65 66 const topo_method_t hc_methods[] = { 67 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 68 TOPO_STABILITY_INTERNAL, hc_fmri_nvl2str }, 69 { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 70 TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl }, 71 { TOPO_METH_COMPARE, TOPO_METH_COMPARE_DESC, TOPO_METH_COMPARE_VERSION, 72 TOPO_STABILITY_INTERNAL, hc_compare }, 73 { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, 74 TOPO_STABILITY_INTERNAL, hc_fmri_create_meth }, 75 { NULL } 76 }; 77 78 static const topo_modops_t hc_ops = 79 { hc_enum, hc_release }; 80 static const topo_modinfo_t hc_info = 81 { HC, FM_FMRI_SCHEME_HC, HC_VERSION, &hc_ops }; 82 83 static const hcc_t hc_canon[] = { 84 { BRANCH, TOPO_STABILITY_PRIVATE }, 85 { CMP, TOPO_STABILITY_PRIVATE }, 86 { CENTERPLANE, TOPO_STABILITY_PRIVATE }, 87 { CHASSIS, TOPO_STABILITY_PRIVATE }, 88 { CHIP, TOPO_STABILITY_PRIVATE }, 89 { CHIP_SELECT, TOPO_STABILITY_PRIVATE }, 90 { CPU, TOPO_STABILITY_PRIVATE }, 91 { DIMM, TOPO_STABILITY_PRIVATE }, 92 { DISK, TOPO_STABILITY_PRIVATE }, 93 { DRAMCHANNEL, TOPO_STABILITY_PRIVATE }, 94 { HOSTBRIDGE, TOPO_STABILITY_PRIVATE }, 95 { INTERCONNECT, TOPO_STABILITY_PRIVATE }, 96 { IOBOARD, TOPO_STABILITY_PRIVATE }, 97 { MEMORYCONTROL, TOPO_STABILITY_PRIVATE }, 98 { MOTHERBOARD, TOPO_STABILITY_PRIVATE }, 99 { NIU, TOPO_STABILITY_PRIVATE }, 100 { NIUFN, TOPO_STABILITY_PRIVATE }, 101 { PCI_BUS, TOPO_STABILITY_PRIVATE }, 102 { PCI_DEVICE, TOPO_STABILITY_PRIVATE }, 103 { PCI_FUNCTION, TOPO_STABILITY_PRIVATE }, 104 { PCIEX_BUS, TOPO_STABILITY_PRIVATE }, 105 { PCIEX_DEVICE, TOPO_STABILITY_PRIVATE }, 106 { PCIEX_FUNCTION, TOPO_STABILITY_PRIVATE }, 107 { PCIEX_ROOT, TOPO_STABILITY_PRIVATE }, 108 { PCIEX_SWUP, TOPO_STABILITY_PRIVATE }, 109 { PCIEX_SWDWN, TOPO_STABILITY_PRIVATE }, 110 { RANK, TOPO_STABILITY_PRIVATE }, 111 { SATA_PORT, TOPO_STABILITY_PRIVATE }, 112 { SYSTEMBOARD, TOPO_STABILITY_PRIVATE }, 113 { XAUI, TOPO_STABILITY_PRIVATE }, 114 { XFP, TOPO_STABILITY_PRIVATE } 115 }; 116 117 static int hc_ncanon = sizeof (hc_canon) / sizeof (hcc_t); 118 119 int 120 hc_init(topo_mod_t *mod, topo_version_t version) 121 { 122 /* 123 * Turn on module debugging output 124 */ 125 if (getenv("TOPOHCDEBUG")) 126 topo_mod_setdebug(mod); 127 128 topo_mod_dprintf(mod, "initializing hc builtin\n"); 129 130 if (version != HC_VERSION) 131 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 132 133 if (topo_mod_register(mod, &hc_info, TOPO_VERSION) != 0) { 134 topo_mod_dprintf(mod, "failed to register hc: " 135 "%s\n", topo_mod_errmsg(mod)); 136 return (-1); /* mod errno already set */ 137 } 138 139 return (0); 140 } 141 142 void 143 hc_fini(topo_mod_t *mod) 144 { 145 topo_mod_unregister(mod); 146 } 147 148 149 static const topo_pgroup_info_t sys_pgroup = { 150 TOPO_PGROUP_SYSTEM, 151 TOPO_STABILITY_PRIVATE, 152 TOPO_STABILITY_PRIVATE, 153 1 154 }; 155 156 static const topo_pgroup_info_t auth_pgroup = { 157 FM_FMRI_AUTHORITY, 158 TOPO_STABILITY_PRIVATE, 159 TOPO_STABILITY_PRIVATE, 160 1 161 }; 162 163 static void 164 hc_prop_set(tnode_t *node, nvlist_t *auth) 165 { 166 int err; 167 char isa[MAXNAMELEN]; 168 struct utsname uts; 169 char *prod, *csn, *server; 170 171 if (auth == NULL) 172 return; 173 174 if (topo_pgroup_create(node, &auth_pgroup, &err) != 0) { 175 if (err != ETOPO_PROP_DEFD) 176 return; 177 } 178 179 /* 180 * Inherit if we can, it saves memory 181 */ 182 if (topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT, 183 &err) != 0) { 184 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod) 185 == 0) 186 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 187 FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod, 188 &err); 189 } 190 if (topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS, 191 &err) != 0) { 192 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0) 193 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 194 FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn, 195 &err); 196 } 197 if (topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER, 198 &err) != 0) { 199 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server) 200 == 0) 201 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 202 FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server, 203 &err); 204 } 205 206 if (topo_pgroup_create(node, &sys_pgroup, &err) != 0) 207 return; 208 209 isa[0] = '\0'; 210 (void) sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)); 211 (void) uname(&uts); 212 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA, 213 TOPO_PROP_IMMUTABLE, isa, &err); 214 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, 215 TOPO_PROP_IMMUTABLE, uts.machine, &err); 216 } 217 218 /*ARGSUSED*/ 219 int 220 hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min, 221 topo_instance_t max, void *notused1, void *notused2) 222 { 223 nvlist_t *pfmri = NULL; 224 nvlist_t *nvl; 225 nvlist_t *auth; 226 tnode_t *node; 227 int err; 228 /* 229 * Register root node methods 230 */ 231 if (strcmp(name, HC) == 0) { 232 (void) topo_method_register(mod, pnode, hc_methods); 233 return (0); 234 } 235 if (min != max) { 236 topo_mod_dprintf(mod, 237 "Request to enumerate %s component with an " 238 "ambiguous instance number, min (%d) != max (%d).\n", 239 HC, min, max); 240 return (topo_mod_seterrno(mod, EINVAL)); 241 } 242 243 (void) topo_node_resource(pnode, &pfmri, &err); 244 auth = topo_mod_auth(mod, pnode); 245 nvl = hc_fmri_create(mod, pfmri, FM_HC_SCHEME_VERSION, name, min, 246 auth, NULL, NULL, NULL); 247 nvlist_free(pfmri); /* callee ignores NULLs */ 248 if (nvl == NULL) { 249 nvlist_free(auth); 250 return (-1); 251 } 252 253 if ((node = topo_node_bind(mod, pnode, name, min, nvl)) == NULL) { 254 topo_mod_dprintf(mod, "topo_node_bind failed: %s\n", 255 topo_strerror(topo_mod_errno(mod))); 256 nvlist_free(auth); 257 nvlist_free(nvl); 258 return (-1); 259 } 260 261 hc_prop_set(node, auth); 262 nvlist_free(nvl); 263 nvlist_free(auth); 264 265 return (0); 266 } 267 268 /*ARGSUSED*/ 269 static void 270 hc_release(topo_mod_t *mp, tnode_t *node) 271 { 272 topo_method_unregister_all(mp, node); 273 } 274 275 /*ARGSUSED*/ 276 static int 277 hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version, 278 nvlist_t *in, nvlist_t **out) 279 { 280 uint8_t v1, v2; 281 nvlist_t *nv1, *nv2; 282 nvlist_t **hcp1, **hcp2; 283 int err, i; 284 uint_t nhcp1, nhcp2; 285 286 if (version > TOPO_METH_COMPARE_VERSION) 287 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 288 289 if (nvlist_lookup_nvlist(in, "nv1", &nv1) != 0 || 290 nvlist_lookup_nvlist(in, "nv2", &nv2) != 0) 291 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 292 293 if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 || 294 nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 || 295 v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION) 296 return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION)); 297 298 err = nvlist_lookup_nvlist_array(nv1, FM_FMRI_HC_LIST, &hcp1, &nhcp1); 299 err |= nvlist_lookup_nvlist_array(nv2, FM_FMRI_HC_LIST, &hcp2, &nhcp2); 300 if (err != 0) 301 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 302 303 if (nhcp1 != nhcp2) 304 return (0); 305 306 for (i = 0; i < nhcp1; i++) { 307 char *nm1 = NULL; 308 char *nm2 = NULL; 309 char *id1 = NULL; 310 char *id2 = NULL; 311 312 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_NAME, &nm1); 313 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_NAME, &nm2); 314 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_ID, &id1); 315 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_ID, &id2); 316 if (nm1 == NULL || nm2 == NULL || id1 == NULL || id2 == NULL) 317 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 318 319 if (strcmp(nm1, nm2) == 0 && strcmp(id1, id2) == 0) 320 continue; 321 322 return (0); 323 } 324 325 return (1); 326 } 327 328 static ssize_t 329 fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 330 { 331 nvlist_t **hcprs = NULL; 332 nvlist_t *anvl = NULL; 333 uint8_t version; 334 ssize_t size = 0; 335 uint_t hcnprs; 336 char *achas = NULL; 337 char *adom = NULL; 338 char *aprod = NULL; 339 char *asrvr = NULL; 340 char *ahost = NULL; 341 char *serial = NULL; 342 char *part = NULL; 343 char *root = NULL; 344 char *rev = NULL; 345 int more_auth = 0; 346 int err, i; 347 348 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 349 version > FM_HC_SCHEME_VERSION) 350 return (-1); 351 352 /* Get authority, if present */ 353 err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); 354 if (err != 0 && err != ENOENT) 355 return (-1); 356 357 if ((err = nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root)) != 0) 358 return (-1); 359 360 err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs); 361 if (err != 0 || hcprs == NULL) 362 return (-1); 363 364 if (anvl != NULL) { 365 (void) nvlist_lookup_string(anvl, 366 FM_FMRI_AUTH_PRODUCT, &aprod); 367 (void) nvlist_lookup_string(anvl, 368 FM_FMRI_AUTH_CHASSIS, &achas); 369 (void) nvlist_lookup_string(anvl, 370 FM_FMRI_AUTH_DOMAIN, &adom); 371 (void) nvlist_lookup_string(anvl, 372 FM_FMRI_AUTH_SERVER, &asrvr); 373 (void) nvlist_lookup_string(anvl, 374 FM_FMRI_AUTH_HOST, &ahost); 375 if (aprod != NULL) 376 more_auth++; 377 if (achas != NULL) 378 more_auth++; 379 if (adom != NULL) 380 more_auth++; 381 if (asrvr != NULL) 382 more_auth++; 383 if (ahost != NULL) 384 more_auth++; 385 } 386 387 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial); 388 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part); 389 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev); 390 391 /* hc:// */ 392 topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://"); 393 394 /* authority, if any */ 395 if (aprod != NULL) 396 topo_fmristr_build(&size, 397 buf, buflen, aprod, ":" FM_FMRI_AUTH_PRODUCT "=", NULL); 398 if (achas != NULL) 399 topo_fmristr_build(&size, 400 buf, buflen, achas, ":" FM_FMRI_AUTH_CHASSIS "=", NULL); 401 if (adom != NULL) 402 topo_fmristr_build(&size, 403 buf, buflen, adom, ":" FM_FMRI_AUTH_DOMAIN "=", NULL); 404 if (asrvr != NULL) 405 topo_fmristr_build(&size, 406 buf, buflen, asrvr, ":" FM_FMRI_AUTH_SERVER "=", NULL); 407 if (ahost != NULL) 408 topo_fmristr_build(&size, 409 buf, buflen, ahost, ":" FM_FMRI_AUTH_HOST "=", NULL); 410 411 /* hardware-id part */ 412 topo_fmristr_build(&size, 413 buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", NULL); 414 topo_fmristr_build(&size, 415 buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL); 416 topo_fmristr_build(&size, 417 buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL); 418 419 /* separating slash */ 420 topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL); 421 422 /* hc-root */ 423 topo_fmristr_build(&size, buf, buflen, root, NULL, NULL); 424 425 /* all the pairs */ 426 for (i = 0; i < hcnprs; i++) { 427 char *nm = NULL; 428 char *id = NULL; 429 430 if (i > 0) 431 topo_fmristr_build(&size, 432 buf, buflen, "/", NULL, NULL); 433 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm); 434 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id); 435 if (nm == NULL || id == NULL) 436 return (0); 437 topo_fmristr_build(&size, buf, buflen, nm, NULL, "="); 438 topo_fmristr_build(&size, buf, buflen, id, NULL, NULL); 439 } 440 441 return (size); 442 } 443 444 /*ARGSUSED*/ 445 static int 446 hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 447 nvlist_t *nvl, nvlist_t **out) 448 { 449 ssize_t len; 450 char *name = NULL; 451 nvlist_t *fmristr; 452 453 if (version > TOPO_METH_NVL2STR_VERSION) 454 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 455 456 if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 || 457 (name = topo_mod_alloc(mod, len + 1)) == NULL || 458 fmri_nvl2str(nvl, name, len + 1) == 0) { 459 if (name != NULL) 460 topo_mod_free(mod, name, len + 1); 461 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 462 } 463 464 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) 465 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 466 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 467 topo_mod_free(mod, name, len + 1); 468 nvlist_free(fmristr); 469 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 470 } 471 topo_mod_free(mod, name, len + 1); 472 *out = fmristr; 473 474 return (0); 475 } 476 477 static nvlist_t * 478 hc_base_fmri_create(topo_mod_t *mod, const nvlist_t *auth, const char *part, 479 const char *rev, const char *serial) 480 { 481 nvlist_t *fmri; 482 int err = 0; 483 484 /* 485 * Create base HC nvlist 486 */ 487 if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 488 return (NULL); 489 490 err = nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION); 491 err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC); 492 err |= nvlist_add_string(fmri, FM_FMRI_HC_ROOT, ""); 493 if (err != 0) { 494 nvlist_free(fmri); 495 return (NULL); 496 } 497 498 /* 499 * Add optional payload members 500 */ 501 if (serial != NULL) 502 (void) nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID, serial); 503 if (part != NULL) 504 (void) nvlist_add_string(fmri, FM_FMRI_HC_PART, part); 505 if (rev != NULL) 506 (void) nvlist_add_string(fmri, FM_FMRI_HC_REVISION, rev); 507 if (auth != NULL) 508 (void) nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, 509 (nvlist_t *)auth); 510 511 return (fmri); 512 } 513 514 static nvlist_t ** 515 make_hc_pairs(topo_mod_t *mod, char *fmri, int *num) 516 { 517 nvlist_t **pa; 518 char *hc, *fromstr; 519 char *starti, *startn, *endi, *endi2; 520 char *ne, *ns; 521 char *cname; 522 char *find; 523 char *cid; 524 int nslashes = 0; 525 int npairs = 0; 526 int i, e; 527 528 if ((hc = topo_mod_strdup(mod, fmri + 5)) == NULL) 529 return (NULL); 530 531 /* 532 * Count equal signs and slashes to determine how many 533 * hc-pairs will be present in the final FMRI. There should 534 * be at least as many slashes as equal signs. There can be 535 * more, though if the string after an = includes them. 536 */ 537 if ((fromstr = strchr(hc, '/')) == NULL) 538 return (NULL); 539 540 find = fromstr; 541 while ((ne = strchr(find, '=')) != NULL) { 542 find = ne + 1; 543 npairs++; 544 } 545 546 find = fromstr; 547 while ((ns = strchr(find, '/')) != NULL) { 548 find = ns + 1; 549 nslashes++; 550 } 551 552 /* 553 * Do we appear to have a well-formed string version of the FMRI? 554 */ 555 if (nslashes < npairs || npairs == 0) { 556 topo_mod_strfree(mod, hc); 557 return (NULL); 558 } 559 560 *num = npairs; 561 562 find = fromstr; 563 564 pa = topo_mod_alloc(mod, npairs * sizeof (nvlist_t *)); 565 /* 566 * We go through a pretty complicated procedure to find the 567 * name and id for each pair. That's because, unfortunately, 568 * we have some ids that can have slashes within them. So 569 * we can't just search for the next slash after the equal sign 570 * and decide that starts a new pair. Instead we have to find 571 * an equal sign for the next pair and work our way back to the 572 * slash from there. 573 */ 574 for (i = 0; i < npairs; i++) { 575 pa[i] = NULL; 576 startn = strchr(find, '/'); 577 if (startn == NULL) 578 break; 579 startn++; 580 starti = strchr(find, '='); 581 if (starti == NULL) 582 break; 583 *starti = '\0'; 584 cname = topo_mod_strdup(mod, startn); 585 *starti++ = '='; 586 endi = strchr(starti, '='); 587 if (endi != NULL) { 588 *endi = '\0'; 589 endi2 = strrchr(starti, '/'); 590 if (endi2 == NULL) 591 break; 592 *endi = '='; 593 *endi2 = '\0'; 594 cid = topo_mod_strdup(mod, starti); 595 *endi2 = '/'; 596 find = endi2; 597 } else { 598 cid = topo_mod_strdup(mod, starti); 599 find = starti + strlen(starti); 600 } 601 if ((e = topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME)) != 0) { 602 topo_mod_strfree(mod, cname); 603 topo_mod_strfree(mod, cid); 604 break; 605 } 606 607 e = nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname); 608 e |= nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid); 609 610 topo_mod_strfree(mod, cname); 611 topo_mod_strfree(mod, cid); 612 613 if (e != 0) { 614 break; 615 } 616 } 617 if (i < npairs) { 618 while (i >= 0) 619 if (pa[i--] != NULL) 620 nvlist_free(pa[i + 1]); 621 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 622 topo_mod_strfree(mod, hc); 623 return (NULL); 624 } 625 626 topo_mod_strfree(mod, hc); 627 628 return (pa); 629 } 630 631 void 632 make_hc_auth(topo_mod_t *mod, char *fmri, char **serial, char **part, 633 char **rev, nvlist_t **auth) 634 { 635 char *starti, *startn, *endi, *copy; 636 char *aname, *aid, *fs; 637 nvlist_t *na = NULL; 638 size_t len; 639 640 if ((copy = topo_mod_strdup(mod, fmri + 5)) == NULL) 641 return; 642 643 len = strlen(copy); 644 645 /* 646 * Make sure there are a valid authority members 647 */ 648 startn = strchr(copy, ':'); 649 fs = strchr(copy, '/'); 650 651 if (startn == NULL || fs == NULL) { 652 topo_mod_strfree(mod, copy); 653 return; 654 } 655 656 /* 657 * The first colon we encounter must occur before the 658 * first slash 659 */ 660 if (startn > fs) 661 return; 662 663 do { 664 if (++startn >= copy + len) 665 break; 666 667 if ((starti = strchr(startn, '=')) == NULL) 668 break; 669 670 *starti = '\0'; 671 if (++starti > copy + len) 672 break; 673 674 if ((aname = topo_mod_strdup(mod, startn)) == NULL) 675 break; 676 677 startn = endi = strchr(starti, ':'); 678 if (endi == NULL) 679 if ((endi = strchr(starti, '/')) == NULL) 680 break; 681 682 *endi = '\0'; 683 if ((aid = topo_mod_strdup(mod, starti)) == NULL) { 684 topo_mod_strfree(mod, aname); 685 break; 686 } 687 688 /* 689 * Return possible serial, part and revision 690 */ 691 if (strcmp(aname, FM_FMRI_HC_SERIAL_ID) == 0) { 692 *serial = topo_mod_strdup(mod, aid); 693 } else if (strcmp(aname, FM_FMRI_HC_PART) == 0) { 694 *part = topo_mod_strdup(mod, aid); 695 } else if (strcmp(aname, FM_FMRI_HC_REVISION) == 0) { 696 *rev = topo_mod_strdup(mod, aid); 697 } else { 698 if (na == NULL) { 699 if (topo_mod_nvalloc(mod, &na, 700 NV_UNIQUE_NAME) == 0) { 701 (void) nvlist_add_string(na, aname, aid); 702 } 703 } else { 704 (void) nvlist_add_string(na, aname, aid); 705 } 706 } 707 topo_mod_strfree(mod, aname); 708 topo_mod_strfree(mod, aid); 709 710 } while (startn != NULL); 711 712 *auth = na; 713 714 topo_mod_free(mod, copy, len + 1); 715 } 716 717 /*ARGSUSED*/ 718 static int 719 hc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 720 nvlist_t *in, nvlist_t **out) 721 { 722 nvlist_t **pa = NULL; 723 nvlist_t *nf = NULL; 724 nvlist_t *auth = NULL; 725 char *str; 726 char *serial = NULL, *part = NULL, *rev = NULL; 727 int npairs; 728 int i, e; 729 730 if (version > TOPO_METH_STR2NVL_VERSION) 731 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 732 733 if (nvlist_lookup_string(in, "fmri-string", &str) != 0) 734 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 735 736 /* We're expecting a string version of an hc scheme FMRI */ 737 if (strncmp(str, "hc://", 5) != 0) 738 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 739 740 if ((pa = make_hc_pairs(mod, str, &npairs)) == NULL) 741 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 742 743 make_hc_auth(mod, str, &serial, &part, &rev, &auth); 744 if ((nf = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL) 745 goto hcfmbail; 746 if ((e = nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, npairs)) == 0) 747 e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, npairs); 748 if (e != 0) { 749 topo_mod_dprintf(mod, "construction of new hc nvl failed"); 750 goto hcfmbail; 751 } 752 for (i = 0; i < npairs; i++) 753 nvlist_free(pa[i]); 754 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 755 if (serial != NULL) 756 topo_mod_strfree(mod, serial); 757 if (part != NULL) 758 topo_mod_strfree(mod, part); 759 if (rev != NULL) 760 topo_mod_strfree(mod, rev); 761 nvlist_free(auth); 762 763 *out = nf; 764 765 return (0); 766 767 hcfmbail: 768 if (nf != NULL) 769 nvlist_free(nf); 770 for (i = 0; i < npairs; i++) 771 nvlist_free(pa[i]); 772 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 773 if (serial != NULL) 774 topo_mod_strfree(mod, serial); 775 if (part != NULL) 776 topo_mod_strfree(mod, part); 777 if (rev != NULL) 778 topo_mod_strfree(mod, rev); 779 nvlist_free(auth); 780 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 781 } 782 783 static nvlist_t * 784 hc_list_create(topo_mod_t *mod, const char *name, char *inst) 785 { 786 int err; 787 nvlist_t *hc; 788 789 if (topo_mod_nvalloc(mod, &hc, NV_UNIQUE_NAME) != 0) 790 return (NULL); 791 792 err = nvlist_add_string(hc, FM_FMRI_HC_NAME, name); 793 err |= nvlist_add_string(hc, FM_FMRI_HC_ID, inst); 794 if (err != 0) { 795 nvlist_free(hc); 796 return (NULL); 797 } 798 799 return (hc); 800 } 801 802 static nvlist_t * 803 hc_create_seterror(topo_mod_t *mod, nvlist_t **hcl, int n, nvlist_t *fmri, 804 int err) 805 { 806 int i; 807 808 if (hcl != NULL) { 809 for (i = 0; i < n + 1; ++i) 810 nvlist_free(hcl[i]); 811 812 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (n + 1)); 813 } 814 815 nvlist_free(fmri); 816 817 (void) topo_mod_seterrno(mod, err); 818 819 topo_mod_dprintf(mod, "unable to create hc FMRI: %s\n", 820 topo_mod_errmsg(mod)); 821 822 return (NULL); 823 } 824 825 static int 826 hc_name_canonical(topo_mod_t *mod, const char *name) 827 { 828 int i; 829 830 if (getenv("NOHCCHECK") != NULL) 831 return (1); 832 833 /* 834 * Only enumerate elements with correct canonical names 835 */ 836 for (i = 0; i < hc_ncanon; i++) { 837 if (strcmp(name, hc_canon[i].hcc_name) == 0) 838 break; 839 } 840 if (i >= hc_ncanon) { 841 topo_mod_dprintf(mod, "non-canonical name %s\n", 842 name); 843 return (0); 844 } else { 845 return (1); 846 } 847 } 848 849 static nvlist_t * 850 hc_fmri_create(topo_mod_t *mod, nvlist_t *pfmri, int version, const char *name, 851 topo_instance_t inst, const nvlist_t *auth, const char *part, 852 const char *rev, const char *serial) 853 { 854 int i; 855 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 856 uint_t pelems = 0; 857 nvlist_t **phcl = NULL; 858 nvlist_t **hcl = NULL; 859 nvlist_t *fmri = NULL; 860 861 if (version > FM_HC_SCHEME_VERSION) 862 return (hc_create_seterror(mod, 863 hcl, pelems, fmri, EMOD_VER_OLD)); 864 else if (version < FM_HC_SCHEME_VERSION) 865 return (hc_create_seterror(mod, 866 hcl, pelems, fmri, EMOD_VER_NEW)); 867 868 /* 869 * Check that the requested name is in our canonical list 870 */ 871 if (hc_name_canonical(mod, name) == 0) 872 return (hc_create_seterror(mod, 873 hcl, pelems, fmri, EMOD_NONCANON)); 874 /* 875 * Copy the parent's HC_LIST 876 */ 877 if (pfmri != NULL) { 878 if (nvlist_lookup_nvlist_array(pfmri, FM_FMRI_HC_LIST, 879 &phcl, &pelems) != 0) 880 return (hc_create_seterror(mod, 881 hcl, pelems, fmri, EMOD_FMRI_MALFORM)); 882 } 883 884 hcl = topo_mod_zalloc(mod, sizeof (nvlist_t *) * (pelems + 1)); 885 if (hcl == NULL) 886 return (hc_create_seterror(mod, hcl, pelems, fmri, 887 EMOD_NOMEM)); 888 889 for (i = 0; i < pelems; ++i) 890 if (topo_mod_nvdup(mod, phcl[i], &hcl[i]) != 0) 891 return (hc_create_seterror(mod, 892 hcl, pelems, fmri, EMOD_FMRI_NVL)); 893 894 (void) snprintf(str, sizeof (str), "%d", inst); 895 if ((hcl[i] = hc_list_create(mod, name, str)) == NULL) 896 return (hc_create_seterror(mod, 897 hcl, pelems, fmri, EMOD_FMRI_NVL)); 898 899 if ((fmri = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL) 900 return (hc_create_seterror(mod, 901 hcl, pelems, fmri, EMOD_FMRI_NVL)); 902 903 if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, hcl, pelems + 1) 904 != 0) 905 return (hc_create_seterror(mod, 906 hcl, pelems, fmri, EMOD_FMRI_NVL)); 907 908 if (hcl != NULL) { 909 for (i = 0; i < pelems + 1; ++i) { 910 if (hcl[i] != NULL) 911 nvlist_free(hcl[i]); 912 } 913 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (pelems + 1)); 914 } 915 916 return (fmri); 917 } 918 919 /*ARGSUSED*/ 920 static int 921 hc_fmri_create_meth(topo_mod_t *mod, tnode_t *node, topo_version_t version, 922 nvlist_t *in, nvlist_t **out) 923 { 924 int ret; 925 nvlist_t *args, *pfmri = NULL; 926 nvlist_t *auth; 927 uint32_t inst; 928 char *name, *serial, *rev, *part; 929 930 if (version > TOPO_METH_FMRI_VERSION) 931 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 932 933 /* First the must-have fields */ 934 if (nvlist_lookup_string(in, TOPO_METH_FMRI_ARG_NAME, &name) != 0) 935 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 936 if (nvlist_lookup_uint32(in, TOPO_METH_FMRI_ARG_INST, &inst) != 0) 937 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 938 939 /* 940 * args is optional 941 */ 942 pfmri = NULL; 943 auth = NULL; 944 serial = rev = part = NULL; 945 if ((ret = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args)) 946 != 0) { 947 if (ret != ENOENT) 948 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 949 } else { 950 951 /* And then optional arguments */ 952 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, 953 &pfmri); 954 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, 955 &auth); 956 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_PART, 957 &part); 958 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_REV, &rev); 959 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_SER, 960 &serial); 961 } 962 963 *out = hc_fmri_create(mod, pfmri, version, name, inst, auth, part, 964 rev, serial); 965 if (*out == NULL) 966 return (-1); 967 return (0); 968 } 969