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 2007 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. 322 */ 323 char * 324 topo_cleanup_auth_str(topo_hdl_t *thp, char *begin) 325 { 326 char buf[MAXNAMELEN]; 327 size_t count; 328 char *str, *end, *pp; 329 330 end = begin + strlen(begin); 331 332 while (begin < end && isspace(*begin)) 333 begin++; 334 while (begin < end && isspace(*(end - 1))) 335 end--; 336 337 if (begin >= end) 338 return (NULL); 339 340 count = end - begin; 341 count += 1; 342 343 if (count > sizeof (buf)) 344 return (NULL); 345 346 (void) snprintf(buf, count, "%s", begin); 347 while ((str = strpbrk(buf, " :=")) != NULL) 348 *str = '-'; 349 350 pp = topo_hdl_strdup(thp, buf); 351 return (pp); 352 } 353