1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 /* 26 * Copyright 2020 Joyent, Inc. 27 * Copyright 2023 Oxide Computer Company 28 */ 29 30 #include <alloca.h> 31 #include <ctype.h> 32 #include <limits.h> 33 #include <syslog.h> 34 #include <strings.h> 35 #include <unistd.h> 36 #include <sys/fm/protocol.h> 37 #include <sys/systeminfo.h> 38 #include <sys/utsname.h> 39 40 #include <topo_error.h> 41 #include <topo_digraph.h> 42 #include <topo_subr.h> 43 44 void 45 topo_hdl_lock(topo_hdl_t *thp) 46 { 47 (void) pthread_mutex_lock(&thp->th_lock); 48 } 49 50 void 51 topo_hdl_unlock(topo_hdl_t *thp) 52 { 53 (void) pthread_mutex_unlock(&thp->th_lock); 54 } 55 56 const char * 57 topo_stability2name(topo_stability_t s) 58 { 59 switch (s) { 60 case TOPO_STABILITY_INTERNAL: return (TOPO_STABSTR_INTERNAL); 61 case TOPO_STABILITY_PRIVATE: return (TOPO_STABSTR_PRIVATE); 62 case TOPO_STABILITY_OBSOLETE: return (TOPO_STABSTR_OBSOLETE); 63 case TOPO_STABILITY_EXTERNAL: return (TOPO_STABSTR_EXTERNAL); 64 case TOPO_STABILITY_UNSTABLE: return (TOPO_STABSTR_UNSTABLE); 65 case TOPO_STABILITY_EVOLVING: return (TOPO_STABSTR_EVOLVING); 66 case TOPO_STABILITY_STABLE: return (TOPO_STABSTR_STABLE); 67 case TOPO_STABILITY_STANDARD: return (TOPO_STABSTR_STANDARD); 68 default: return (TOPO_STABSTR_UNKNOWN); 69 } 70 } 71 72 topo_stability_t 73 topo_name2stability(const char *name) 74 { 75 if (strcmp(name, TOPO_STABSTR_INTERNAL) == 0) 76 return (TOPO_STABILITY_INTERNAL); 77 else if (strcmp(name, TOPO_STABSTR_PRIVATE) == 0) 78 return (TOPO_STABILITY_PRIVATE); 79 else if (strcmp(name, TOPO_STABSTR_OBSOLETE) == 0) 80 return (TOPO_STABILITY_OBSOLETE); 81 else if (strcmp(name, TOPO_STABSTR_EXTERNAL) == 0) 82 return (TOPO_STABILITY_EXTERNAL); 83 else if (strcmp(name, TOPO_STABSTR_UNSTABLE) == 0) 84 return (TOPO_STABILITY_UNSTABLE); 85 else if (strcmp(name, TOPO_STABSTR_EVOLVING) == 0) 86 return (TOPO_STABILITY_EVOLVING); 87 else if (strcmp(name, TOPO_STABSTR_STABLE) == 0) 88 return (TOPO_STABILITY_STABLE); 89 else if (strcmp(name, TOPO_STABSTR_STANDARD) == 0) 90 return (TOPO_STABILITY_STANDARD); 91 92 return (TOPO_STABILITY_UNKNOWN); 93 } 94 95 static const topo_debug_mode_t _topo_dbout_modes[] = { 96 { "stderr", "send debug messages to stderr", TOPO_DBOUT_STDERR }, 97 { "syslog", "send debug messages to syslog", TOPO_DBOUT_SYSLOG }, 98 { NULL, NULL, 0 } 99 }; 100 101 static const topo_debug_mode_t _topo_dbflag_modes[] = { 102 { "error", "error handling debug messages enabled", TOPO_DBG_ERR }, 103 { "module", "module debug messages enabled", TOPO_DBG_MOD }, 104 { "modulesvc", "module services debug messages enabled", 105 TOPO_DBG_MODSVC }, 106 { "walk", "walker subsystem debug messages enabled", TOPO_DBG_WALK }, 107 { "xml", "xml file parsing messages enabled", TOPO_DBG_XML }, 108 { "devinfoforce", "devinfo DINFOFORCE snapshot used", TOPO_DBG_FORCE }, 109 { "all", "all debug modes enabled", TOPO_DBG_ALL}, 110 { NULL, NULL, 0 } 111 }; 112 113 void 114 env_process_value(topo_hdl_t *thp, const char *begin, const char *end) 115 { 116 char buf[MAXNAMELEN]; 117 size_t count; 118 topo_debug_mode_t *dbp; 119 120 while (begin < end && isspace(*begin)) 121 begin++; 122 123 while (begin < end && isspace(*(end - 1))) 124 end--; 125 126 if (begin >= end) 127 return; 128 129 count = end - begin; 130 count += 1; 131 132 if (count > sizeof (buf)) 133 return; 134 135 (void) snprintf(buf, count, "%s", begin); 136 137 for (dbp = (topo_debug_mode_t *)_topo_dbflag_modes; 138 dbp->tdm_name != NULL; ++dbp) { 139 if (strcmp(buf, dbp->tdm_name) == 0) 140 thp->th_debug |= dbp->tdm_mode; 141 } 142 } 143 144 void 145 topo_debug_set(topo_hdl_t *thp, const char *dbmode, const char *dout) 146 { 147 char *end, *value, *next; 148 topo_debug_mode_t *dbp; 149 150 topo_hdl_lock(thp); 151 value = (char *)dbmode; 152 153 for (end = (char *)dbmode; *end != '\0'; value = next) { 154 end = strchr(value, ','); 155 if (end != NULL) 156 next = end + 1; /* skip the comma */ 157 else 158 next = end = value + strlen(value); 159 160 env_process_value(thp, value, end); 161 } 162 163 if (dout == NULL) { 164 topo_hdl_unlock(thp); 165 return; 166 } 167 168 for (dbp = (topo_debug_mode_t *)_topo_dbout_modes; 169 dbp->tdm_name != NULL; ++dbp) { 170 if (strcmp(dout, dbp->tdm_name) == 0) 171 thp->th_dbout = dbp->tdm_mode; 172 } 173 topo_hdl_unlock(thp); 174 } 175 176 void 177 topo_vdprintf(topo_hdl_t *thp, const char *mod, const char *format, va_list ap) 178 { 179 char *msg; 180 size_t len; 181 char c; 182 183 len = vsnprintf(&c, 1, format, ap); 184 msg = alloca(len + 2); 185 (void) vsnprintf(msg, len + 1, format, ap); 186 187 if (msg[len - 1] != '\n') 188 (void) strcpy(&msg[len], "\n"); 189 190 if (thp->th_dbout == TOPO_DBOUT_SYSLOG) { 191 if (mod == NULL) { 192 syslog(LOG_DEBUG | LOG_USER, "libtopo DEBUG: %s", msg); 193 } else { 194 syslog(LOG_DEBUG | LOG_USER, "libtopo DEBUG: %s: %s", 195 mod, msg); 196 } 197 } else { 198 if (mod == NULL) { 199 (void) fprintf(stderr, "libtopo DEBUG: %s", msg); 200 } else { 201 (void) fprintf(stderr, "libtopo DEBUG: %s: %s", mod, 202 msg); 203 } 204 } 205 } 206 207 /*PRINTFLIKE3*/ 208 void 209 topo_dprintf(topo_hdl_t *thp, int mask, const char *format, ...) 210 { 211 va_list ap; 212 213 if (!(thp->th_debug & mask)) 214 return; 215 216 va_start(ap, format); 217 topo_vdprintf(thp, NULL, format, ap); 218 va_end(ap); 219 } 220 221 tnode_t * 222 topo_hdl_root(topo_hdl_t *thp, const char *scheme) 223 { 224 ttree_t *tp; 225 topo_digraph_t *tdg; 226 227 for (tp = topo_list_next(&thp->th_trees); tp != NULL; 228 tp = topo_list_next(tp)) { 229 if (strcmp(scheme, tp->tt_scheme) == 0) 230 return (tp->tt_root); 231 } 232 for (tdg = topo_list_next(&thp->th_digraphs); tdg != NULL; 233 tdg = topo_list_next(tdg)) { 234 if (strcmp(scheme, tdg->tdg_scheme) == 0) 235 return (tdg->tdg_rootnode); 236 } 237 238 return (NULL); 239 } 240 241 /* 242 * buf_append -- Append str to buf (if it's non-NULL). Place prepend 243 * in buf in front of str and append behind it (if they're non-NULL). 244 * Continue to update size even if we run out of space to actually 245 * stuff characters in the buffer. 246 */ 247 void 248 topo_fmristr_build(ssize_t *sz, char *buf, size_t buflen, char *str, 249 char *prepend, char *append) 250 { 251 ssize_t left; 252 253 if (str == NULL) 254 return; 255 256 if (buflen == 0 || (left = buflen - *sz) < 0) 257 left = 0; 258 259 if (buf != NULL && left != 0) 260 buf += *sz; 261 262 if (prepend == NULL && append == NULL) 263 *sz += snprintf(buf, left, "%s", str); 264 else if (append == NULL) 265 *sz += snprintf(buf, left, "%s%s", prepend, str); 266 else if (prepend == NULL) 267 *sz += snprintf(buf, left, "%s%s", str, append); 268 else 269 *sz += snprintf(buf, left, "%s%s%s", prepend, str, append); 270 } 271 272 #define TOPO_PLATFORM_PATH "%s/usr/platform/%s/lib/fm/topo/%s" 273 #define TOPO_COMMON_PATH "%s/usr/lib/fm/topo/%s" 274 275 char * 276 topo_search_path(topo_mod_t *mod, const char *rootdir, const char *file) 277 { 278 char *pp, sp[PATH_MAX]; 279 topo_hdl_t *thp = mod->tm_hdl; 280 281 /* 282 * Search for file name in order of platform, machine and common 283 * topo directories 284 */ 285 (void) snprintf(sp, PATH_MAX, TOPO_PLATFORM_PATH, rootdir, 286 thp->th_platform, file); 287 if (access(sp, F_OK) != 0) { 288 (void) snprintf(sp, PATH_MAX, TOPO_PLATFORM_PATH, 289 thp->th_rootdir, thp->th_machine, file); 290 if (access(sp, F_OK) != 0) { 291 (void) snprintf(sp, PATH_MAX, TOPO_COMMON_PATH, 292 thp->th_rootdir, file); 293 if (access(sp, F_OK) != 0) { 294 return (NULL); 295 } 296 } 297 } 298 299 pp = topo_mod_strdup(mod, sp); 300 301 return (pp); 302 } 303 304 /* 305 * SMBIOS serial numbers (and many other strings from devices) can contain 306 * characters (particularly ':' and ' ') that are invalid for the authority and 307 * can break FMRI parsing. We translate any invalid characters to a safe '-', 308 * as well as trimming any leading or trailing whitespace. Similarly, '/' can 309 * be found in some product names so we translate that to '-'. 310 */ 311 char * 312 topo_cleanup_strn(topo_hdl_t *thp, const char *begin, size_t max) 313 { 314 char buf[MAXNAMELEN]; 315 const char *end, *cp; 316 char *pp; 317 char c; 318 size_t i; 319 320 end = begin + max; 321 322 while (begin < end && isspace(*begin)) 323 begin++; 324 while (begin < end && (isspace(*(end - 1)) || *(end - 1) == '\0')) 325 end--; 326 327 if (begin >= end) 328 return (NULL); 329 330 cp = begin; 331 for (i = 0; i < MAXNAMELEN - 1; i++) { 332 if (cp >= end) 333 break; 334 c = *cp; 335 if (c == ':' || c == '=' || c == '/' || isspace(c) || 336 !isprint(c)) 337 buf[i] = '-'; 338 else 339 buf[i] = c; 340 cp++; 341 } 342 buf[i] = 0; 343 344 pp = topo_hdl_strdup(thp, buf); 345 return (pp); 346 } 347 348 char * 349 topo_cleanup_auth_str(topo_hdl_t *thp, const char *begin) 350 { 351 return (topo_cleanup_strn(thp, begin, strlen(begin))); 352 } 353 354 void 355 topo_sensor_type_name(uint32_t type, char *buf, size_t len) 356 { 357 topo_name_trans_t *ntp; 358 359 for (ntp = &topo_sensor_type_table[0]; ntp->int_name != NULL; ntp++) { 360 if (ntp->int_value == type) { 361 (void) strlcpy(buf, ntp->int_name, len); 362 return; 363 } 364 } 365 366 (void) snprintf(buf, len, "0x%02x", type); 367 } 368 369 void 370 topo_sensor_units_name(uint8_t type, char *buf, size_t len) 371 { 372 topo_name_trans_t *ntp; 373 374 for (ntp = &topo_units_type_table[0]; ntp->int_name != NULL; ntp++) { 375 if (ntp->int_value == type) { 376 (void) strlcpy(buf, ntp->int_name, len); 377 return; 378 } 379 } 380 381 (void) snprintf(buf, len, "0x%02x", type); 382 } 383 384 void 385 topo_led_type_name(uint8_t type, char *buf, size_t len) 386 { 387 topo_name_trans_t *ntp; 388 389 for (ntp = &topo_led_type_table[0]; ntp->int_name != NULL; ntp++) { 390 if (ntp->int_value == type) { 391 (void) strlcpy(buf, ntp->int_name, len); 392 return; 393 } 394 } 395 396 (void) snprintf(buf, len, "0x%02x", type); 397 } 398 399 void 400 topo_led_state_name(uint8_t type, char *buf, size_t len) 401 { 402 topo_name_trans_t *ntp; 403 404 for (ntp = &topo_led_states_table[0]; ntp->int_name != NULL; ntp++) { 405 if (ntp->int_value == type) { 406 (void) strlcpy(buf, ntp->int_name, len); 407 return; 408 } 409 } 410 411 (void) snprintf(buf, len, "0x%02x", type); 412 } 413 414 void 415 topo_sensor_state_name(uint32_t sensor_type, uint8_t state, char *buf, 416 size_t len) 417 { 418 topo_name_trans_t *ntp; 419 420 switch (sensor_type) { 421 case TOPO_SENSOR_TYPE_PHYSICAL: 422 ntp = &topo_sensor_states_physical_table[0]; 423 break; 424 case TOPO_SENSOR_TYPE_PLATFORM: 425 ntp = &topo_sensor_states_platform_table[0]; 426 break; 427 case TOPO_SENSOR_TYPE_PROCESSOR: 428 ntp = &topo_sensor_states_processor_table[0]; 429 break; 430 case TOPO_SENSOR_TYPE_POWER_SUPPLY: 431 ntp = &topo_sensor_states_power_supply_table[0]; 432 break; 433 case TOPO_SENSOR_TYPE_POWER_UNIT: 434 ntp = &topo_sensor_states_power_unit_table[0]; 435 break; 436 case TOPO_SENSOR_TYPE_MEMORY: 437 ntp = &topo_sensor_states_memory_table[0]; 438 break; 439 case TOPO_SENSOR_TYPE_BAY: 440 ntp = &topo_sensor_states_bay_table[0]; 441 break; 442 case TOPO_SENSOR_TYPE_FIRMWARE: 443 ntp = &topo_sensor_states_firmware_table[0]; 444 break; 445 case TOPO_SENSOR_TYPE_EVENT_LOG: 446 ntp = &topo_sensor_states_event_log_table[0]; 447 break; 448 case TOPO_SENSOR_TYPE_WATCHDOG1: 449 ntp = &topo_sensor_states_watchdog1_table[0]; 450 break; 451 case TOPO_SENSOR_TYPE_SYSTEM: 452 ntp = &topo_sensor_states_system_table[0]; 453 break; 454 case TOPO_SENSOR_TYPE_CRITICAL: 455 ntp = &topo_sensor_states_critical_table[0]; 456 break; 457 case TOPO_SENSOR_TYPE_BUTTON: 458 ntp = &topo_sensor_states_button_table[0]; 459 break; 460 case TOPO_SENSOR_TYPE_CABLE: 461 ntp = &topo_sensor_states_cable_table[0]; 462 break; 463 case TOPO_SENSOR_TYPE_BOOT_STATE: 464 ntp = &topo_sensor_states_boot_state_table[0]; 465 break; 466 case TOPO_SENSOR_TYPE_BOOT_ERROR: 467 ntp = &topo_sensor_states_boot_error_table[0]; 468 break; 469 case TOPO_SENSOR_TYPE_BOOT_OS: 470 ntp = &topo_sensor_states_boot_os_table[0]; 471 break; 472 case TOPO_SENSOR_TYPE_OS_SHUTDOWN: 473 ntp = &topo_sensor_states_os_table[0]; 474 break; 475 case TOPO_SENSOR_TYPE_SLOT: 476 ntp = &topo_sensor_states_slot_table[0]; 477 break; 478 case TOPO_SENSOR_TYPE_ACPI: 479 ntp = &topo_sensor_states_acpi_table[0]; 480 break; 481 case TOPO_SENSOR_TYPE_WATCHDOG2: 482 ntp = &topo_sensor_states_watchdog2_table[0]; 483 break; 484 case TOPO_SENSOR_TYPE_ALERT: 485 ntp = &topo_sensor_states_alert_table[0]; 486 break; 487 case TOPO_SENSOR_TYPE_PRESENCE: 488 ntp = &topo_sensor_states_presence_table[0]; 489 break; 490 case TOPO_SENSOR_TYPE_LAN: 491 ntp = &topo_sensor_states_lan_table[0]; 492 break; 493 case TOPO_SENSOR_TYPE_HEALTH: 494 ntp = &topo_sensor_states_health_table[0]; 495 break; 496 case TOPO_SENSOR_TYPE_BATTERY: 497 ntp = &topo_sensor_states_battery_table[0]; 498 break; 499 case TOPO_SENSOR_TYPE_AUDIT: 500 ntp = &topo_sensor_states_audit_table[0]; 501 break; 502 case TOPO_SENSOR_TYPE_VERSION: 503 ntp = &topo_sensor_states_version_table[0]; 504 break; 505 case TOPO_SENSOR_TYPE_FRU_STATE: 506 ntp = &topo_sensor_states_fru_state_table[0]; 507 break; 508 case TOPO_SENSOR_TYPE_THRESHOLD_STATE: 509 ntp = &topo_sensor_states_thresh_table[0]; 510 break; 511 case TOPO_SENSOR_TYPE_GENERIC_USAGE: 512 ntp = &topo_sensor_states_generic_usage_table[0]; 513 break; 514 case TOPO_SENSOR_TYPE_GENERIC_STATE: 515 ntp = &topo_sensor_states_generic_state_table[0]; 516 break; 517 case TOPO_SENSOR_TYPE_GENERIC_PREDFAIL: 518 ntp = &topo_sensor_states_generic_predfail_table[0]; 519 break; 520 case TOPO_SENSOR_TYPE_GENERIC_LIMIT: 521 ntp = &topo_sensor_states_generic_limit_table[0]; 522 break; 523 case TOPO_SENSOR_TYPE_GENERIC_PERFORMANCE: 524 ntp = &topo_sensor_states_generic_perf_table[0]; 525 break; 526 case TOPO_SENSOR_TYPE_SEVERITY: 527 ntp = &topo_sensor_states_severity_table[0]; 528 break; 529 case TOPO_SENSOR_TYPE_GENERIC_PRESENCE: 530 ntp = &topo_sensor_states_generic_presence_table[0]; 531 break; 532 case TOPO_SENSOR_TYPE_GENERIC_AVAILABILITY: 533 ntp = &topo_sensor_states_generic_avail_table[0]; 534 break; 535 case TOPO_SENSOR_TYPE_GENERIC_STATUS: 536 ntp = &topo_sensor_states_generic_status_table[0]; 537 break; 538 case TOPO_SENSOR_TYPE_GENERIC_ACPI: 539 ntp = &topo_sensor_states_generic_acpi_pwr_table[0]; 540 break; 541 case TOPO_SENSOR_TYPE_GENERIC_FAILURE: 542 ntp = &topo_sensor_states_generic_failure_table[0]; 543 break; 544 case TOPO_SENSOR_TYPE_GENERIC_OK: 545 ntp = &topo_sensor_states_generic_ok_table[0]; 546 break; 547 default: 548 (void) snprintf(buf, len, "0x%02x", state); 549 return; 550 } 551 if (state == 0) { 552 (void) snprintf(buf, len, "NO_STATES_ASSERTED"); 553 return; 554 } 555 buf[0] = '\0'; 556 for (; ntp->int_name != NULL; ntp++) { 557 if (state & ntp->int_value) { 558 if (buf[0] != '\0') 559 (void) strlcat(buf, "|", len); 560 (void) strlcat(buf, ntp->int_name, len); 561 } 562 } 563 564 if (buf[0] == '\0') 565 (void) snprintf(buf, len, "0x%02x", state); 566 } 567 568 static const topo_pgroup_info_t sys_pgroup = { 569 TOPO_PGROUP_SYSTEM, 570 TOPO_STABILITY_PRIVATE, 571 TOPO_STABILITY_PRIVATE, 572 1 573 }; 574 static const topo_pgroup_info_t auth_pgroup = { 575 FM_FMRI_AUTHORITY, 576 TOPO_STABILITY_PRIVATE, 577 TOPO_STABILITY_PRIVATE, 578 1 579 }; 580 581 void 582 topo_pgroup_hcset(tnode_t *node, nvlist_t *auth) 583 { 584 int err; 585 char isa[MAXNAMELEN]; 586 struct utsname uts; 587 char *prod, *psn, *csn, *server; 588 589 if (auth == NULL) 590 return; 591 592 if (topo_pgroup_create(node, &auth_pgroup, &err) != 0) { 593 if (err != ETOPO_PROP_DEFD) 594 return; 595 } 596 597 /* 598 * Inherit if we can, it saves memory 599 */ 600 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT, 601 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 602 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod) == 603 0) 604 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 605 FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod, 606 &err); 607 } 608 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT_SN, 609 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 610 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, &psn) == 611 0) 612 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 613 FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn, 614 &err); 615 } 616 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS, 617 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 618 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0) 619 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 620 FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn, 621 &err); 622 } 623 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER, 624 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 625 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server) == 626 0) 627 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 628 FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server, 629 &err); 630 } 631 632 if (topo_pgroup_create(node, &sys_pgroup, &err) != 0) 633 return; 634 635 if (sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)) != -1) 636 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, 637 TOPO_PROP_ISA, TOPO_PROP_IMMUTABLE, isa, &err); 638 639 if (uname(&uts) != -1) 640 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, 641 TOPO_PROP_MACHINE, TOPO_PROP_IMMUTABLE, uts.machine, &err); 642 } 643