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