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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/systeminfo.h> 28 29 #include <limits.h> 30 #include <strings.h> 31 #include <stddef.h> 32 #include <unistd.h> 33 #include <dlfcn.h> 34 #include <errno.h> 35 36 #include <fmdump.h> 37 38 /* 39 * fmdump loadable scheme support 40 * 41 * This file provides a pared-down implementation of fmd's fmd_fmri.c and 42 * fmd_scheme.c and must be kept in sync with the set of service routines 43 * required by scheme plug-ins. At some point if other utilities want to 44 * use this we can refactor it into a more general library. (Note: fmd 45 * cannot use such a library because it has its own internal locking, etc.) 46 * As schemes are needed, we dlopen() them and cache a list of them which we 47 * can search later. We also use the list as a negative cache: if we fail to 48 * load a scheme, we add an entry with sch_dlp = NULL and sch_err recording 49 * the errno to be returned to the caller. 50 */ 51 52 typedef struct fmd_scheme_ops { 53 int (*sop_init)(void); 54 void (*sop_fini)(void); 55 ssize_t (*sop_nvl2str)(nvlist_t *, char *, size_t); 56 } fmd_scheme_ops_t; 57 58 typedef struct fmd_scheme_opd { 59 const char *opd_name; /* symbol name of scheme function */ 60 size_t opd_off; /* offset within fmd_scheme_ops_t */ 61 } fmd_scheme_opd_t; 62 63 typedef struct fmd_scheme { 64 struct fmd_scheme *sch_next; /* next scheme on list of schemes */ 65 char *sch_name; /* name of this scheme (fmri prefix) */ 66 void *sch_dlp; /* libdl(3DL) shared library handle */ 67 int sch_err; /* if negative entry, errno to return */ 68 fmd_scheme_ops_t sch_ops; /* scheme function pointers */ 69 } fmd_scheme_t; 70 71 static fmd_scheme_t *sch_list; /* list of cached schemes */ 72 73 static long 74 fmd_scheme_notsup(void) 75 { 76 errno = ENOTSUP; 77 return (-1); 78 } 79 80 static void 81 fmd_scheme_vnop(void) 82 { 83 } 84 85 static int 86 fmd_scheme_nop(void) 87 { 88 return (0); 89 } 90 91 /* 92 * Default values for the scheme ops. If a scheme function is not defined in 93 * the module, then this operation is implemented using the default function. 94 */ 95 static const fmd_scheme_ops_t _fmd_scheme_default_ops = { 96 (int (*)())fmd_scheme_nop, /* sop_init */ 97 (void (*)())fmd_scheme_vnop, /* sop_fini */ 98 (ssize_t (*)())fmd_scheme_notsup, /* sop_nvl2str */ 99 }; 100 101 /* 102 * Scheme ops descriptions. These names and offsets are used by the function 103 * fmd_scheme_rtld_init(), defined below, to load up a fmd_scheme_ops_t. 104 */ 105 static const fmd_scheme_opd_t _fmd_scheme_ops[] = { 106 { "fmd_fmri_init", offsetof(fmd_scheme_ops_t, sop_init) }, 107 { "fmd_fmri_fini", offsetof(fmd_scheme_ops_t, sop_fini) }, 108 { "fmd_fmri_nvl2str", offsetof(fmd_scheme_ops_t, sop_nvl2str) }, 109 { NULL, 0 } 110 }; 111 112 static fmd_scheme_t * 113 fmd_scheme_create(const char *name) 114 { 115 fmd_scheme_t *sp; 116 117 if ((sp = malloc(sizeof (fmd_scheme_t))) == NULL || 118 (sp->sch_name = strdup(name)) == NULL) { 119 free(sp); 120 return (NULL); 121 } 122 123 sp->sch_next = sch_list; 124 sp->sch_dlp = NULL; 125 sp->sch_err = 0; 126 sp->sch_ops = _fmd_scheme_default_ops; 127 128 sch_list = sp; 129 return (sp); 130 } 131 132 static int 133 fmd_scheme_rtld_init(fmd_scheme_t *sp) 134 { 135 const fmd_scheme_opd_t *opd; 136 void *p; 137 138 for (opd = _fmd_scheme_ops; opd->opd_name != NULL; opd++) { 139 if ((p = dlsym(sp->sch_dlp, opd->opd_name)) != NULL) 140 *(void **)((uintptr_t)&sp->sch_ops + opd->opd_off) = p; 141 } 142 143 return (sp->sch_ops.sop_init()); 144 } 145 146 static fmd_scheme_t * 147 fmd_scheme_lookup(const char *dir, const char *name) 148 { 149 fmd_scheme_t *sp; 150 char path[PATH_MAX]; 151 152 for (sp = sch_list; sp != NULL; sp = sp->sch_next) { 153 if (strcmp(name, sp->sch_name) == 0) 154 return (sp); 155 } 156 157 if ((sp = fmd_scheme_create(name)) == NULL) 158 return (NULL); /* errno is set for us */ 159 160 (void) snprintf(path, sizeof (path), "%s%s/%s.so", 161 g_root ? g_root : "", dir, name); 162 163 if (access(path, F_OK) != 0) { 164 sp->sch_err = errno; 165 return (sp); 166 } 167 168 if ((sp->sch_dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW)) == NULL) { 169 sp->sch_err = ELIBACC; 170 return (sp); 171 } 172 173 if (fmd_scheme_rtld_init(sp) != 0) { 174 sp->sch_err = errno; 175 (void) dlclose(sp->sch_dlp); 176 sp->sch_dlp = NULL; 177 } 178 179 return (sp); 180 } 181 182 char * 183 fmdump_nvl2str(nvlist_t *nvl) 184 { 185 fmd_scheme_t *sp; 186 char c, *name, *s = NULL; 187 ssize_t len; 188 189 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) { 190 fmdump_warn("fmri does not contain required '%s' nvpair\n", 191 FM_FMRI_SCHEME); 192 return (NULL); 193 } 194 195 if ((sp = fmd_scheme_lookup("/usr/lib/fm/fmd/schemes", name)) == NULL || 196 sp->sch_dlp == NULL || sp->sch_err != 0) { 197 const char *msg = 198 sp->sch_err == ELIBACC ? dlerror() : strerror(sp->sch_err); 199 200 fmdump_warn("cannot init '%s' scheme library to " 201 "format fmri: %s\n", name, msg ? msg : "unknown error"); 202 203 return (NULL); 204 } 205 206 if ((len = sp->sch_ops.sop_nvl2str(nvl, &c, sizeof (c))) == -1 || 207 (s = malloc(len + 1)) == NULL || 208 sp->sch_ops.sop_nvl2str(nvl, s, len + 1) == -1) { 209 fmdump_warn("cannot format fmri using scheme '%s'", name); 210 free(s); 211 return (NULL); 212 } 213 214 return (s); 215 } 216 217 218 void * 219 fmd_fmri_alloc(size_t size) 220 { 221 return (malloc(size)); 222 } 223 224 void * 225 fmd_fmri_zalloc(size_t size) 226 { 227 void *data; 228 229 if ((data = malloc(size)) != NULL) 230 bzero(data, size); 231 232 return (data); 233 } 234 235 /*ARGSUSED*/ 236 void 237 fmd_fmri_free(void *data, size_t size) 238 { 239 free(data); 240 } 241 242 int 243 fmd_fmri_error(int err) 244 { 245 errno = err; 246 return (-1); 247 } 248 249 char * 250 fmd_fmri_strescape(const char *s) 251 { 252 return (strdup(s)); 253 } 254 255 char * 256 fmd_fmri_strdup(const char *s) 257 { 258 return (strdup(s)); 259 } 260 261 void 262 fmd_fmri_strfree(char *s) 263 { 264 free(s); 265 } 266 267 const char * 268 fmd_fmri_get_rootdir(void) 269 { 270 return (g_root ? g_root : ""); 271 } 272 273 const char * 274 fmd_fmri_get_platform(void) 275 { 276 static char platform[MAXNAMELEN]; 277 278 if (platform[0] == '\0') 279 (void) sysinfo(SI_PLATFORM, platform, sizeof (platform)); 280 281 return (platform); 282 } 283 284 uint64_t 285 fmd_fmri_get_drgen(void) 286 { 287 return (0); 288 } 289 290 int 291 fmd_fmri_set_errno(int err) 292 { 293 errno = err; 294 return (-1); 295 } 296 297 void 298 fmd_fmri_warn(const char *format, ...) 299 { 300 va_list ap; 301 302 va_start(ap, format); 303 fmdump_vwarn(format, ap); 304 va_end(ap); 305 } 306 307 struct topo_hdl * 308 fmd_fmri_topo_hold(int version) 309 { 310 int err; 311 312 if (version != TOPO_VERSION) 313 return (NULL); 314 315 if (g_thp == NULL) { 316 if ((g_thp = topo_open(TOPO_VERSION, "/", &err)) == NULL) { 317 (void) fprintf(stderr, "topo_open failed: %s\n", 318 topo_strerror(err)); 319 exit(1); 320 } 321 } 322 323 return (g_thp); 324 } 325 326 /*ARGSUSED*/ 327 void 328 fmd_fmri_topo_rele(struct topo_hdl *thp) 329 { 330 /* nothing to do */ 331 } 332