#include <sys/types.h>
#include <sys/systeminfo.h>
#include <limits.h>
#include <strings.h>
#include <stddef.h>
#include <unistd.h>
#include <dlfcn.h>
#include <errno.h>
#include <fmdump.h>
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;
size_t opd_off;
} fmd_scheme_opd_t;
typedef struct fmd_scheme {
struct fmd_scheme *sch_next;
char *sch_name;
void *sch_dlp;
int sch_err;
fmd_scheme_ops_t sch_ops;
} fmd_scheme_t;
static fmd_scheme_t *sch_list;
static long
fmd_scheme_notsup(void)
{
errno = ENOTSUP;
return (-1);
}
static void
fmd_scheme_vnop(void)
{
}
static int
fmd_scheme_nop(void)
{
return (0);
}
static const fmd_scheme_ops_t _fmd_scheme_default_ops = {
(int (*)())fmd_scheme_nop,
(void (*)())fmd_scheme_vnop,
(ssize_t (*)())fmd_scheme_notsup,
};
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);
(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)) == 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 *
fmdump_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) {
fmdump_warn("fmri does not contain required '%s' nvpair\n",
FM_FMRI_SCHEME);
return (NULL);
}
if ((sp = fmd_scheme_lookup("/usr/lib/fm/fmd/schemes", name)) == NULL ||
sp->sch_dlp == NULL || sp->sch_err != 0) {
const char *msg =
sp->sch_err == ELIBACC ? dlerror() : strerror(sp->sch_err);
fmdump_warn("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) {
fmdump_warn("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);
}
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);
}
void
fmd_fmri_warn(const char *format, ...)
{
va_list ap;
va_start(ap, format);
fmdump_vwarn(format, ap);
va_end(ap);
}
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) {
(void) fprintf(stderr, "topo_open failed: %s\n",
topo_strerror(err));
exit(1);
}
}
return (g_thp);
}
void
fmd_fmri_topo_rele(struct topo_hdl *thp)
{
}