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 55typedef 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 61typedef 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 66typedef 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 74static fmd_scheme_t *sch_list; /* list of cached schemes */ 75static char *g_root; /* fmd root dir */ 76static struct topo_hdl *g_thp; 77 78static long 79fmd_scheme_notsup(void) 80{ 81 errno = ENOTSUP; 82 return (-1); 83} 84 85static int 86fmd_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 */ 95static 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 */ 105static 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 112static fmd_scheme_t * 113fmd_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 132static int 133fmd_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 146static fmd_scheme_t * 147fmd_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 183char * 184sunFm_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 217void * 218fmd_fmri_alloc(size_t size) 219{ 220 return (malloc(size)); 221} 222 223void * 224fmd_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*/ 235void 236fmd_fmri_free(void *data, size_t size) 237{ 238 free(data); 239} 240 241int 242fmd_fmri_error(int err) 243{ 244 errno = err; 245 return (-1); 246} 247 248char * 249fmd_fmri_strescape(const char *s) 250{ 251 return (strdup(s)); 252} 253 254char * 255fmd_fmri_strdup(const char *s) 256{ 257 return (strdup(s)); 258} 259 260void 261fmd_fmri_strfree(char *s) 262{ 263 free(s); 264} 265 266const char * 267fmd_fmri_get_rootdir(void) 268{ 269 return (g_root ? g_root : ""); 270} 271 272const char * 273fmd_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 283uint64_t 284fmd_fmri_get_drgen(void) 285{ 286 return (0); 287} 288 289int 290fmd_fmri_set_errno(int err) 291{ 292 errno = err; 293 return (-1); 294} 295 296/*ARGSUSED*/ 297void 298fmd_fmri_warn(const char *format, ...) 299{ 300} 301 302struct topo_hdl * 303fmd_fmri_topo_hold(int version) 304{ 305 int err; 306 307 if (version != TOPO_VERSION) 308 return (NULL); 309 310 if (g_thp == NULL) { 311 if ((g_thp = topo_open(TOPO_VERSION, "/", &err)) == NULL) { 312 DEBUGMSGTL((MODNAME_STR, "topo_open failed: %s\n", 313 topo_strerror(err))); 314 return (NULL); 315 } 316 } 317 318 return (g_thp); 319} 320 321/*ARGSUSED*/ 322void 323fmd_fmri_topo_rele(struct topo_hdl *thp) 324{ 325 /* nothing to do */ 326} 327