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 <sys/fm/protocol.h> 30 #include <sys/types.h> 31 #include <sys/systeminfo.h> 32 #include <fm/fmd_snmp.h> 33 #include <fm/libtopo.h> 34 #include <net-snmp/net-snmp-config.h> 35 #include <net-snmp/net-snmp-includes.h> 36 #include <net-snmp/agent/net-snmp-agent-includes.h> 37 #include <libnvpair.h> 38 #include <limits.h> 39 #include <strings.h> 40 #include <stddef.h> 41 #include <unistd.h> 42 #include <dlfcn.h> 43 #include <errno.h> 44 45 #define SCHEMEDIR_BASE "/usr/lib/fm/fmd/schemes" 46 47 #if defined(__sparcv9) 48 #define DEFAULTSCHEMEDIR SCHEMEDIR_BASE "/sparcv9" 49 #elif defined(__amd64) 50 #define DEFAULTSCHEMEDIR SCHEMEDIR_BASE "/amd64" 51 #else 52 #define DEFAULTSCHEMEDIR SCHEMEDIR_BASE 53 #endif 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 static char *g_root; /* fmd root dir */ 76 static struct topo_hdl *g_thp; 77 78 static long 79 fmd_scheme_notsup(void) 80 { 81 errno = ENOTSUP; 82 return (-1); 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_nop, /* 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 | RTLD_PARENT)) == 169 NULL) { 170 sp->sch_err = ELIBACC; 171 return (sp); 172 } 173 174 if (fmd_scheme_rtld_init(sp) != 0) { 175 sp->sch_err = errno; 176 (void) dlclose(sp->sch_dlp); 177 sp->sch_dlp = NULL; 178 } 179 180 return (sp); 181 } 182 183 char * 184 sunFm_nvl2str(nvlist_t *nvl) 185 { 186 fmd_scheme_t *sp; 187 char c, *name, *s = NULL; 188 ssize_t len; 189 190 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) { 191 DEBUGMSGTL((MODNAME_STR, "fmri does not contain required " 192 "'%s' nvpair\n", FM_FMRI_SCHEME)); 193 return (NULL); 194 } 195 196 if ((sp = fmd_scheme_lookup(DEFAULTSCHEMEDIR, name)) == NULL || 197 sp->sch_dlp == NULL || sp->sch_err != 0) { 198 const char *msg = 199 sp->sch_err == ELIBACC ? dlerror() : strerror(sp->sch_err); 200 DEBUGMSGTL((MODNAME_STR, "cannot init '%s' scheme library to " 201 "format fmri: %s\n", name, msg ? msg : "unknown error")); 202 return (NULL); 203 } 204 205 if ((len = sp->sch_ops.sop_nvl2str(nvl, &c, sizeof (c))) == -1 || 206 (s = malloc(len + 1)) == NULL || 207 sp->sch_ops.sop_nvl2str(nvl, s, len + 1) == -1) { 208 DEBUGMSGTL((MODNAME_STR, "cannot format fmri using scheme '%s'", 209 name)); 210 free(s); 211 return (NULL); 212 } 213 214 return (s); 215 } 216 217 void * 218 fmd_fmri_alloc(size_t size) 219 { 220 return (malloc(size)); 221 } 222 223 void * 224 fmd_fmri_zalloc(size_t size) 225 { 226 void *data; 227 228 if ((data = malloc(size)) != NULL) 229 bzero(data, size); 230 231 return (data); 232 } 233 234 /*ARGSUSED*/ 235 void 236 fmd_fmri_free(void *data, size_t size) 237 { 238 free(data); 239 } 240 241 int 242 fmd_fmri_error(int err) 243 { 244 errno = err; 245 return (-1); 246 } 247 248 char * 249 fmd_fmri_strescape(const char *s) 250 { 251 return (strdup(s)); 252 } 253 254 char * 255 fmd_fmri_strdup(const char *s) 256 { 257 return (strdup(s)); 258 } 259 260 void 261 fmd_fmri_strfree(char *s) 262 { 263 free(s); 264 } 265 266 const char * 267 fmd_fmri_get_rootdir(void) 268 { 269 return (g_root ? g_root : ""); 270 } 271 272 const char * 273 fmd_fmri_get_platform(void) 274 { 275 static char platform[MAXNAMELEN]; 276 277 if (platform[0] == '\0') 278 (void) sysinfo(SI_PLATFORM, platform, sizeof (platform)); 279 280 return (platform); 281 } 282 283 uint64_t 284 fmd_fmri_get_drgen(void) 285 { 286 return (0); 287 } 288 289 int 290 fmd_fmri_set_errno(int err) 291 { 292 errno = err; 293 return (-1); 294 } 295 296 /*ARGSUSED*/ 297 void 298 fmd_fmri_warn(const char *format, ...) 299 { 300 } 301 302 /*ARGSUSED*/ 303 struct topo_hdl * 304 fmd_fmri_topology(int version) 305 { 306 int err; 307 308 if (g_thp == NULL) { 309 if ((g_thp = topo_open(TOPO_VERSION, "/", &err)) == NULL) { 310 DEBUGMSGTL((MODNAME_STR, "topo_open failed: %s\n", 311 topo_strerror(err))); 312 return (NULL); 313 } 314 } 315 316 return (g_thp); 317 } 318