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) 2018, 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, int mask, const char *mod, const char *format, 176 va_list ap) 177 { 178 char *msg; 179 size_t len; 180 char c; 181 182 if (!(thp->th_debug & mask)) 183 return; 184 185 len = vsnprintf(&c, 1, format, ap); 186 msg = alloca(len + 2); 187 (void) vsnprintf(msg, len + 1, format, ap); 188 189 if (msg[len - 1] != '\n') 190 (void) strcpy(&msg[len], "\n"); 191 192 if (thp->th_dbout == TOPO_DBOUT_SYSLOG) { 193 if (mod == NULL) { 194 syslog(LOG_DEBUG | LOG_USER, "libtopo DEBUG: %s", msg); 195 } else { 196 syslog(LOG_DEBUG | LOG_USER, "libtopo DEBUG: %s: %s", 197 mod, msg); 198 } 199 } else { 200 if (mod == NULL) { 201 (void) fprintf(stderr, "libtopo DEBUG: %s", msg); 202 } else { 203 (void) fprintf(stderr, "libtopo DEBUG: %s: %s", mod, 204 msg); 205 } 206 } 207 } 208 209 /*PRINTFLIKE3*/ 210 void 211 topo_dprintf(topo_hdl_t *thp, int mask, const char *format, ...) 212 { 213 va_list ap; 214 215 va_start(ap, format); 216 topo_vdprintf(thp, mask, NULL, format, ap); 217 va_end(ap); 218 } 219 220 tnode_t * 221 topo_hdl_root(topo_hdl_t *thp, const char *scheme) 222 { 223 ttree_t *tp; 224 225 for (tp = topo_list_next(&thp->th_trees); tp != NULL; 226 tp = topo_list_next(tp)) { 227 if (strcmp(scheme, tp->tt_scheme) == 0) 228 return (tp->tt_root); 229 } 230 231 return (NULL); 232 } 233 234 /* 235 * buf_append -- Append str to buf (if it's non-NULL). Place prepend 236 * in buf in front of str and append behind it (if they're non-NULL). 237 * Continue to update size even if we run out of space to actually 238 * stuff characters in the buffer. 239 */ 240 void 241 topo_fmristr_build(ssize_t *sz, char *buf, size_t buflen, char *str, 242 char *prepend, char *append) 243 { 244 ssize_t left; 245 246 if (str == NULL) 247 return; 248 249 if (buflen == 0 || (left = buflen - *sz) < 0) 250 left = 0; 251 252 if (buf != NULL && left != 0) 253 buf += *sz; 254 255 if (prepend == NULL && append == NULL) 256 *sz += snprintf(buf, left, "%s", str); 257 else if (append == NULL) 258 *sz += snprintf(buf, left, "%s%s", prepend, str); 259 else if (prepend == NULL) 260 *sz += snprintf(buf, left, "%s%s", str, append); 261 else 262 *sz += snprintf(buf, left, "%s%s%s", prepend, str, append); 263 } 264 265 #define TOPO_PLATFORM_PATH "%s/usr/platform/%s/lib/fm/topo/%s" 266 #define TOPO_COMMON_PATH "%s/usr/lib/fm/topo/%s" 267 268 char * 269 topo_search_path(topo_mod_t *mod, const char *rootdir, const char *file) 270 { 271 char *pp, sp[PATH_MAX]; 272 topo_hdl_t *thp = mod->tm_hdl; 273 274 /* 275 * Search for file name in order of platform, machine and common 276 * topo directories 277 */ 278 (void) snprintf(sp, PATH_MAX, TOPO_PLATFORM_PATH, rootdir, 279 thp->th_platform, file); 280 if (access(sp, F_OK) != 0) { 281 (void) snprintf(sp, PATH_MAX, TOPO_PLATFORM_PATH, 282 thp->th_rootdir, thp->th_machine, file); 283 if (access(sp, F_OK) != 0) { 284 (void) snprintf(sp, PATH_MAX, TOPO_COMMON_PATH, 285 thp->th_rootdir, file); 286 if (access(sp, F_OK) != 0) { 287 return (NULL); 288 } 289 } 290 } 291 292 pp = topo_mod_strdup(mod, sp); 293 294 return (pp); 295 } 296 297 /* 298 * SMBIOS serial numbers can contain characters (particularly ':' and ' ') 299 * that are invalid for the authority and can break FMRI parsing. We translate 300 * any invalid characters to a safe '-', as well as trimming any leading or 301 * trailing whitespace. Similarly, '/' can be found in some product names 302 * so we translate that to '-'. 303 */ 304 char * 305 topo_cleanup_auth_str(topo_hdl_t *thp, const char *begin) 306 { 307 char buf[MAXNAMELEN]; 308 const char *end, *cp; 309 char *pp; 310 char c; 311 int i; 312 313 end = begin + strlen(begin); 314 315 while (begin < end && isspace(*begin)) 316 begin++; 317 while (begin < end && isspace(*(end - 1))) 318 end--; 319 320 if (begin >= end) 321 return (NULL); 322 323 cp = begin; 324 for (i = 0; i < MAXNAMELEN - 1; i++) { 325 if (cp >= end) 326 break; 327 c = *cp; 328 if (c == ':' || c == '=' || c == '/' || isspace(c) || 329 !isprint(c)) 330 buf[i] = '-'; 331 else 332 buf[i] = c; 333 cp++; 334 } 335 buf[i] = 0; 336 337 pp = topo_hdl_strdup(thp, buf); 338 return (pp); 339 } 340 341 void 342 topo_sensor_type_name(uint32_t type, char *buf, size_t len) 343 { 344 topo_name_trans_t *ntp; 345 346 for (ntp = &topo_sensor_type_table[0]; ntp->int_name != NULL; ntp++) { 347 if (ntp->int_value == type) { 348 (void) strlcpy(buf, ntp->int_name, len); 349 return; 350 } 351 } 352 353 (void) snprintf(buf, len, "0x%02x", type); 354 } 355 356 void 357 topo_sensor_units_name(uint8_t type, char *buf, size_t len) 358 { 359 topo_name_trans_t *ntp; 360 361 for (ntp = &topo_units_type_table[0]; ntp->int_name != NULL; ntp++) { 362 if (ntp->int_value == type) { 363 (void) strlcpy(buf, ntp->int_name, len); 364 return; 365 } 366 } 367 368 (void) snprintf(buf, len, "0x%02x", type); 369 } 370 371 void 372 topo_led_type_name(uint8_t type, char *buf, size_t len) 373 { 374 topo_name_trans_t *ntp; 375 376 for (ntp = &topo_led_type_table[0]; ntp->int_name != NULL; ntp++) { 377 if (ntp->int_value == type) { 378 (void) strlcpy(buf, ntp->int_name, len); 379 return; 380 } 381 } 382 383 (void) snprintf(buf, len, "0x%02x", type); 384 } 385 386 void 387 topo_led_state_name(uint8_t type, char *buf, size_t len) 388 { 389 topo_name_trans_t *ntp; 390 391 for (ntp = &topo_led_states_table[0]; ntp->int_name != NULL; ntp++) { 392 if (ntp->int_value == type) { 393 (void) strlcpy(buf, ntp->int_name, len); 394 return; 395 } 396 } 397 398 (void) snprintf(buf, len, "0x%02x", type); 399 } 400 401 void 402 topo_sensor_state_name(uint32_t sensor_type, uint8_t state, char *buf, 403 size_t len) 404 { 405 topo_name_trans_t *ntp; 406 407 switch (sensor_type) { 408 case TOPO_SENSOR_TYPE_PHYSICAL: 409 ntp = &topo_sensor_states_physical_table[0]; 410 break; 411 case TOPO_SENSOR_TYPE_PLATFORM: 412 ntp = &topo_sensor_states_platform_table[0]; 413 break; 414 case TOPO_SENSOR_TYPE_PROCESSOR: 415 ntp = &topo_sensor_states_processor_table[0]; 416 break; 417 case TOPO_SENSOR_TYPE_POWER_SUPPLY: 418 ntp = &topo_sensor_states_power_supply_table[0]; 419 break; 420 case TOPO_SENSOR_TYPE_POWER_UNIT: 421 ntp = &topo_sensor_states_power_unit_table[0]; 422 break; 423 case TOPO_SENSOR_TYPE_MEMORY: 424 ntp = &topo_sensor_states_memory_table[0]; 425 break; 426 case TOPO_SENSOR_TYPE_BAY: 427 ntp = &topo_sensor_states_bay_table[0]; 428 break; 429 case TOPO_SENSOR_TYPE_FIRMWARE: 430 ntp = &topo_sensor_states_firmware_table[0]; 431 break; 432 case TOPO_SENSOR_TYPE_EVENT_LOG: 433 ntp = &topo_sensor_states_event_log_table[0]; 434 break; 435 case TOPO_SENSOR_TYPE_WATCHDOG1: 436 ntp = &topo_sensor_states_watchdog1_table[0]; 437 break; 438 case TOPO_SENSOR_TYPE_SYSTEM: 439 ntp = &topo_sensor_states_system_table[0]; 440 break; 441 case TOPO_SENSOR_TYPE_CRITICAL: 442 ntp = &topo_sensor_states_critical_table[0]; 443 break; 444 case TOPO_SENSOR_TYPE_BUTTON: 445 ntp = &topo_sensor_states_button_table[0]; 446 break; 447 case TOPO_SENSOR_TYPE_CABLE: 448 ntp = &topo_sensor_states_cable_table[0]; 449 break; 450 case TOPO_SENSOR_TYPE_BOOT_STATE: 451 ntp = &topo_sensor_states_boot_state_table[0]; 452 break; 453 case TOPO_SENSOR_TYPE_BOOT_ERROR: 454 ntp = &topo_sensor_states_boot_error_table[0]; 455 break; 456 case TOPO_SENSOR_TYPE_BOOT_OS: 457 ntp = &topo_sensor_states_boot_os_table[0]; 458 break; 459 case TOPO_SENSOR_TYPE_OS_SHUTDOWN: 460 ntp = &topo_sensor_states_os_table[0]; 461 break; 462 case TOPO_SENSOR_TYPE_SLOT: 463 ntp = &topo_sensor_states_slot_table[0]; 464 break; 465 case TOPO_SENSOR_TYPE_ACPI: 466 ntp = &topo_sensor_states_acpi_table[0]; 467 break; 468 case TOPO_SENSOR_TYPE_WATCHDOG2: 469 ntp = &topo_sensor_states_watchdog2_table[0]; 470 break; 471 case TOPO_SENSOR_TYPE_ALERT: 472 ntp = &topo_sensor_states_alert_table[0]; 473 break; 474 case TOPO_SENSOR_TYPE_PRESENCE: 475 ntp = &topo_sensor_states_presence_table[0]; 476 break; 477 case TOPO_SENSOR_TYPE_LAN: 478 ntp = &topo_sensor_states_lan_table[0]; 479 break; 480 case TOPO_SENSOR_TYPE_HEALTH: 481 ntp = &topo_sensor_states_health_table[0]; 482 break; 483 case TOPO_SENSOR_TYPE_BATTERY: 484 ntp = &topo_sensor_states_battery_table[0]; 485 break; 486 case TOPO_SENSOR_TYPE_AUDIT: 487 ntp = &topo_sensor_states_audit_table[0]; 488 break; 489 case TOPO_SENSOR_TYPE_VERSION: 490 ntp = &topo_sensor_states_version_table[0]; 491 break; 492 case TOPO_SENSOR_TYPE_FRU_STATE: 493 ntp = &topo_sensor_states_fru_state_table[0]; 494 break; 495 case TOPO_SENSOR_TYPE_THRESHOLD_STATE: 496 ntp = &topo_sensor_states_thresh_table[0]; 497 break; 498 case TOPO_SENSOR_TYPE_GENERIC_USAGE: 499 ntp = &topo_sensor_states_generic_usage_table[0]; 500 break; 501 case TOPO_SENSOR_TYPE_GENERIC_STATE: 502 ntp = &topo_sensor_states_generic_state_table[0]; 503 break; 504 case TOPO_SENSOR_TYPE_GENERIC_PREDFAIL: 505 ntp = &topo_sensor_states_generic_predfail_table[0]; 506 break; 507 case TOPO_SENSOR_TYPE_GENERIC_LIMIT: 508 ntp = &topo_sensor_states_generic_limit_table[0]; 509 break; 510 case TOPO_SENSOR_TYPE_GENERIC_PERFORMANCE: 511 ntp = &topo_sensor_states_generic_perf_table[0]; 512 break; 513 case TOPO_SENSOR_TYPE_SEVERITY: 514 ntp = &topo_sensor_states_severity_table[0]; 515 break; 516 case TOPO_SENSOR_TYPE_GENERIC_PRESENCE: 517 ntp = &topo_sensor_states_generic_presence_table[0]; 518 break; 519 case TOPO_SENSOR_TYPE_GENERIC_AVAILABILITY: 520 ntp = &topo_sensor_states_generic_avail_table[0]; 521 break; 522 case TOPO_SENSOR_TYPE_GENERIC_STATUS: 523 ntp = &topo_sensor_states_generic_status_table[0]; 524 break; 525 case TOPO_SENSOR_TYPE_GENERIC_ACPI: 526 ntp = &topo_sensor_states_generic_acpi_pwr_table[0]; 527 break; 528 case TOPO_SENSOR_TYPE_GENERIC_FAILURE: 529 ntp = &topo_sensor_states_generic_failure_table[0]; 530 break; 531 case TOPO_SENSOR_TYPE_GENERIC_OK: 532 ntp = &topo_sensor_states_generic_ok_table[0]; 533 break; 534 default: 535 (void) snprintf(buf, len, "0x%02x", state); 536 return; 537 } 538 for (; ntp->int_name != NULL; ntp++) { 539 if (ntp->int_value == state) { 540 (void) strlcpy(buf, ntp->int_name, len); 541 return; 542 } 543 } 544 545 (void) snprintf(buf, len, "0x%02x", state); 546 } 547 548 static const topo_pgroup_info_t sys_pgroup = { 549 TOPO_PGROUP_SYSTEM, 550 TOPO_STABILITY_PRIVATE, 551 TOPO_STABILITY_PRIVATE, 552 1 553 }; 554 static const topo_pgroup_info_t auth_pgroup = { 555 FM_FMRI_AUTHORITY, 556 TOPO_STABILITY_PRIVATE, 557 TOPO_STABILITY_PRIVATE, 558 1 559 }; 560 561 void 562 topo_pgroup_hcset(tnode_t *node, nvlist_t *auth) 563 { 564 int err; 565 char isa[MAXNAMELEN]; 566 struct utsname uts; 567 char *prod, *psn, *csn, *server; 568 569 if (auth == NULL) 570 return; 571 572 if (topo_pgroup_create(node, &auth_pgroup, &err) != 0) { 573 if (err != ETOPO_PROP_DEFD) 574 return; 575 } 576 577 /* 578 * Inherit if we can, it saves memory 579 */ 580 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT, 581 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 582 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod) == 583 0) 584 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 585 FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod, 586 &err); 587 } 588 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT_SN, 589 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 590 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, &psn) == 591 0) 592 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 593 FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn, 594 &err); 595 } 596 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS, 597 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 598 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0) 599 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 600 FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn, 601 &err); 602 } 603 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER, 604 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 605 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server) == 606 0) 607 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 608 FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server, 609 &err); 610 } 611 612 if (topo_pgroup_create(node, &sys_pgroup, &err) != 0) 613 return; 614 615 if (sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)) != -1) 616 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, 617 TOPO_PROP_ISA, TOPO_PROP_IMMUTABLE, isa, &err); 618 619 if (uname(&uts) != -1) 620 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, 621 TOPO_PROP_MACHINE, TOPO_PROP_IMMUTABLE, uts.machine, &err); 622 } 623