/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SCHEMEDIR_BASE "/usr/lib/fm/fmd/schemes" #if defined(__sparcv9) #define DEFAULTSCHEMEDIR SCHEMEDIR_BASE "/sparcv9" #elif defined(__amd64) #define DEFAULTSCHEMEDIR SCHEMEDIR_BASE "/amd64" #else #define DEFAULTSCHEMEDIR SCHEMEDIR_BASE #endif typedef struct fmd_scheme_ops { int (*sop_init)(void); void (*sop_fini)(void); ssize_t (*sop_nvl2str)(nvlist_t *, char *, size_t); } fmd_scheme_ops_t; typedef struct fmd_scheme_opd { const char *opd_name; /* symbol name of scheme function */ size_t opd_off; /* offset within fmd_scheme_ops_t */ } fmd_scheme_opd_t; typedef struct fmd_scheme { struct fmd_scheme *sch_next; /* next scheme on list of schemes */ char *sch_name; /* name of this scheme (fmri prefix) */ void *sch_dlp; /* libdl(3DL) shared library handle */ int sch_err; /* if negative entry, errno to return */ fmd_scheme_ops_t sch_ops; /* scheme function pointers */ } fmd_scheme_t; static fmd_scheme_t *sch_list; /* list of cached schemes */ static char *g_root; /* fmd root dir */ static struct topo_hdl *g_thp; static ssize_t fmd_scheme_notsup(nvlist_t *nv __unused, char *arg1 __unused, size_t arg2 __unused) { errno = ENOTSUP; return (-1); } static void fmd_scheme_vnop(void) { } static int fmd_scheme_nop(void) { return (0); } /* * Default values for the scheme ops. If a scheme function is not defined in * the module, then this operation is implemented using the default function. */ static const fmd_scheme_ops_t _fmd_scheme_default_ops = { .sop_init = fmd_scheme_nop, /* sop_init */ .sop_fini = fmd_scheme_vnop, /* sop_fini */ .sop_nvl2str = fmd_scheme_notsup /* sop_nvl2str */ }; /* * Scheme ops descriptions. These names and offsets are used by the function * fmd_scheme_rtld_init(), defined below, to load up a fmd_scheme_ops_t. */ static const fmd_scheme_opd_t _fmd_scheme_ops[] = { { "fmd_fmri_init", offsetof(fmd_scheme_ops_t, sop_init) }, { "fmd_fmri_fini", offsetof(fmd_scheme_ops_t, sop_fini) }, { "fmd_fmri_nvl2str", offsetof(fmd_scheme_ops_t, sop_nvl2str) }, { NULL, 0 } }; static fmd_scheme_t * fmd_scheme_create(const char *name) { fmd_scheme_t *sp; if ((sp = malloc(sizeof (fmd_scheme_t))) == NULL || (sp->sch_name = strdup(name)) == NULL) { free(sp); return (NULL); } sp->sch_next = sch_list; sp->sch_dlp = NULL; sp->sch_err = 0; sp->sch_ops = _fmd_scheme_default_ops; sch_list = sp; return (sp); } static int fmd_scheme_rtld_init(fmd_scheme_t *sp) { const fmd_scheme_opd_t *opd; void *p; for (opd = _fmd_scheme_ops; opd->opd_name != NULL; opd++) { if ((p = dlsym(sp->sch_dlp, opd->opd_name)) != NULL) *(void **)((uintptr_t)&sp->sch_ops + opd->opd_off) = p; } return (sp->sch_ops.sop_init()); } static fmd_scheme_t * fmd_scheme_lookup(const char *dir, const char *name) { fmd_scheme_t *sp; char path[PATH_MAX]; for (sp = sch_list; sp != NULL; sp = sp->sch_next) { if (strcmp(name, sp->sch_name) == 0) return (sp); } if ((sp = fmd_scheme_create(name)) == NULL) return (NULL); /* errno is set for us */ (void) snprintf(path, sizeof (path), "%s%s/%s.so", g_root ? g_root : "", dir, name); if (access(path, F_OK) != 0) { sp->sch_err = errno; return (sp); } if ((sp->sch_dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW | RTLD_PARENT)) == NULL) { sp->sch_err = ELIBACC; return (sp); } if (fmd_scheme_rtld_init(sp) != 0) { sp->sch_err = errno; (void) dlclose(sp->sch_dlp); sp->sch_dlp = NULL; } return (sp); } char * sunFm_nvl2str(nvlist_t *nvl) { fmd_scheme_t *sp; char c, *name, *s = NULL; ssize_t len; if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) { DEBUGMSGTL((MODNAME_STR, "fmri does not contain required " "'%s' nvpair\n", FM_FMRI_SCHEME)); return (NULL); } if ((sp = fmd_scheme_lookup(DEFAULTSCHEMEDIR, name)) == NULL || sp->sch_dlp == NULL || sp->sch_err != 0) { const char *msg = sp->sch_err == ELIBACC ? dlerror() : strerror(sp->sch_err); DEBUGMSGTL((MODNAME_STR, "cannot init '%s' scheme library to " "format fmri: %s\n", name, msg ? msg : "unknown error")); return (NULL); } if ((len = sp->sch_ops.sop_nvl2str(nvl, &c, sizeof (c))) == -1 || (s = malloc(len + 1)) == NULL || sp->sch_ops.sop_nvl2str(nvl, s, len + 1) == -1) { DEBUGMSGTL((MODNAME_STR, "cannot format fmri using scheme '%s'", name)); free(s); return (NULL); } return (s); } void * fmd_fmri_alloc(size_t size) { return (malloc(size)); } void * fmd_fmri_zalloc(size_t size) { void *data; if ((data = malloc(size)) != NULL) bzero(data, size); return (data); } /*ARGSUSED*/ void fmd_fmri_free(void *data, size_t size) { free(data); } int fmd_fmri_error(int err) { errno = err; return (-1); } char * fmd_fmri_strescape(const char *s) { return (strdup(s)); } char * fmd_fmri_strdup(const char *s) { return (strdup(s)); } void fmd_fmri_strfree(char *s) { free(s); } const char * fmd_fmri_get_rootdir(void) { return (g_root ? g_root : ""); } const char * fmd_fmri_get_platform(void) { static char platform[MAXNAMELEN]; if (platform[0] == '\0') (void) sysinfo(SI_PLATFORM, platform, sizeof (platform)); return (platform); } uint64_t fmd_fmri_get_drgen(void) { return (0); } int fmd_fmri_set_errno(int err) { errno = err; return (-1); } /*ARGSUSED*/ void fmd_fmri_warn(const char *format, ...) { } struct topo_hdl * fmd_fmri_topo_hold(int version) { int err; if (version != TOPO_VERSION) return (NULL); if (g_thp == NULL) { if ((g_thp = topo_open(TOPO_VERSION, "/", &err)) == NULL) { DEBUGMSGTL((MODNAME_STR, "topo_open failed: %s\n", topo_strerror(err))); return (NULL); } } return (g_thp); } /*ARGSUSED*/ void fmd_fmri_topo_rele(struct topo_hdl *thp) { /* nothing to do */ }