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