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