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