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