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