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