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