17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*24db4641Seschrock * Common Development and Distribution License (the "License"). 6*24db4641Seschrock * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*24db4641Seschrock * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/types.h> 297c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <limits.h> 327c478bd9Sstevel@tonic-gate #include <strings.h> 337c478bd9Sstevel@tonic-gate #include <stddef.h> 347c478bd9Sstevel@tonic-gate #include <unistd.h> 357c478bd9Sstevel@tonic-gate #include <dlfcn.h> 367c478bd9Sstevel@tonic-gate #include <errno.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <fmdump.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 417c478bd9Sstevel@tonic-gate * fmdump loadable scheme support 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * This file provides a pared-down implementation of fmd's fmd_fmri.c and 447c478bd9Sstevel@tonic-gate * fmd_scheme.c and must be kept in sync with the set of service routines 457c478bd9Sstevel@tonic-gate * required by scheme plug-ins. At some point if other utilities want to 467c478bd9Sstevel@tonic-gate * use this we can refactor it into a more general library. (Note: fmd 477c478bd9Sstevel@tonic-gate * cannot use such a library because it has its own internal locking, etc.) 487c478bd9Sstevel@tonic-gate * As schemes are needed, we dlopen() them and cache a list of them which we 497c478bd9Sstevel@tonic-gate * can search later. We also use the list as a negative cache: if we fail to 507c478bd9Sstevel@tonic-gate * load a scheme, we add an entry with sch_dlp = NULL and sch_err recording 517c478bd9Sstevel@tonic-gate * the errno to be returned to the caller. 527c478bd9Sstevel@tonic-gate */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate typedef struct fmd_scheme_ops { 557c478bd9Sstevel@tonic-gate int (*sop_init)(void); 567c478bd9Sstevel@tonic-gate void (*sop_fini)(void); 577c478bd9Sstevel@tonic-gate ssize_t (*sop_nvl2str)(nvlist_t *, char *, size_t); 587c478bd9Sstevel@tonic-gate } fmd_scheme_ops_t; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate typedef struct fmd_scheme_opd { 617c478bd9Sstevel@tonic-gate const char *opd_name; /* symbol name of scheme function */ 627c478bd9Sstevel@tonic-gate size_t opd_off; /* offset within fmd_scheme_ops_t */ 637c478bd9Sstevel@tonic-gate } fmd_scheme_opd_t; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate typedef struct fmd_scheme { 667c478bd9Sstevel@tonic-gate struct fmd_scheme *sch_next; /* next scheme on list of schemes */ 677c478bd9Sstevel@tonic-gate char *sch_name; /* name of this scheme (fmri prefix) */ 687c478bd9Sstevel@tonic-gate void *sch_dlp; /* libdl(3DL) shared library handle */ 697c478bd9Sstevel@tonic-gate int sch_err; /* if negative entry, errno to return */ 707c478bd9Sstevel@tonic-gate fmd_scheme_ops_t sch_ops; /* scheme function pointers */ 717c478bd9Sstevel@tonic-gate } fmd_scheme_t; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate static fmd_scheme_t *sch_list; /* list of cached schemes */ 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate static long 767c478bd9Sstevel@tonic-gate fmd_scheme_notsup(void) 777c478bd9Sstevel@tonic-gate { 787c478bd9Sstevel@tonic-gate errno = ENOTSUP; 797c478bd9Sstevel@tonic-gate return (-1); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate static int 837c478bd9Sstevel@tonic-gate fmd_scheme_nop(void) 847c478bd9Sstevel@tonic-gate { 857c478bd9Sstevel@tonic-gate return (0); 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * Default values for the scheme ops. If a scheme function is not defined in 907c478bd9Sstevel@tonic-gate * the module, then this operation is implemented using the default function. 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate static const fmd_scheme_ops_t _fmd_scheme_default_ops = { 937c478bd9Sstevel@tonic-gate (int (*)())fmd_scheme_nop, /* sop_init */ 947c478bd9Sstevel@tonic-gate (void (*)())fmd_scheme_nop, /* sop_fini */ 957c478bd9Sstevel@tonic-gate (ssize_t (*)())fmd_scheme_notsup, /* sop_nvl2str */ 967c478bd9Sstevel@tonic-gate }; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * Scheme ops descriptions. These names and offsets are used by the function 1007c478bd9Sstevel@tonic-gate * fmd_scheme_rtld_init(), defined below, to load up a fmd_scheme_ops_t. 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate static const fmd_scheme_opd_t _fmd_scheme_ops[] = { 1037c478bd9Sstevel@tonic-gate { "fmd_fmri_init", offsetof(fmd_scheme_ops_t, sop_init) }, 1047c478bd9Sstevel@tonic-gate { "fmd_fmri_fini", offsetof(fmd_scheme_ops_t, sop_fini) }, 1057c478bd9Sstevel@tonic-gate { "fmd_fmri_nvl2str", offsetof(fmd_scheme_ops_t, sop_nvl2str) }, 1067c478bd9Sstevel@tonic-gate { NULL, 0 } 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate static fmd_scheme_t * 1107c478bd9Sstevel@tonic-gate fmd_scheme_create(const char *name) 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate fmd_scheme_t *sp; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate if ((sp = malloc(sizeof (fmd_scheme_t))) == NULL || 1157c478bd9Sstevel@tonic-gate (sp->sch_name = strdup(name)) == NULL) { 1167c478bd9Sstevel@tonic-gate free(sp); 1177c478bd9Sstevel@tonic-gate return (NULL); 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate sp->sch_next = sch_list; 1217c478bd9Sstevel@tonic-gate sp->sch_dlp = NULL; 1227c478bd9Sstevel@tonic-gate sp->sch_err = 0; 1237c478bd9Sstevel@tonic-gate sp->sch_ops = _fmd_scheme_default_ops; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate sch_list = sp; 1267c478bd9Sstevel@tonic-gate return (sp); 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate static int 1307c478bd9Sstevel@tonic-gate fmd_scheme_rtld_init(fmd_scheme_t *sp) 1317c478bd9Sstevel@tonic-gate { 1327c478bd9Sstevel@tonic-gate const fmd_scheme_opd_t *opd; 1337c478bd9Sstevel@tonic-gate void *p; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate for (opd = _fmd_scheme_ops; opd->opd_name != NULL; opd++) { 1367c478bd9Sstevel@tonic-gate if ((p = dlsym(sp->sch_dlp, opd->opd_name)) != NULL) 1377c478bd9Sstevel@tonic-gate *(void **)((uintptr_t)&sp->sch_ops + opd->opd_off) = p; 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate return (sp->sch_ops.sop_init()); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate static fmd_scheme_t * 1447c478bd9Sstevel@tonic-gate fmd_scheme_lookup(const char *dir, const char *name) 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate fmd_scheme_t *sp; 1477c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate for (sp = sch_list; sp != NULL; sp = sp->sch_next) { 1507c478bd9Sstevel@tonic-gate if (strcmp(name, sp->sch_name) == 0) 1517c478bd9Sstevel@tonic-gate return (sp); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if ((sp = fmd_scheme_create(name)) == NULL) 1557c478bd9Sstevel@tonic-gate return (NULL); /* errno is set for us */ 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s/%s.so", 1587c478bd9Sstevel@tonic-gate g_root ? g_root : "", dir, name); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate if (access(path, F_OK) != 0) { 1617c478bd9Sstevel@tonic-gate sp->sch_err = errno; 1627c478bd9Sstevel@tonic-gate return (sp); 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if ((sp->sch_dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW)) == NULL) { 1667c478bd9Sstevel@tonic-gate sp->sch_err = ELIBACC; 1677c478bd9Sstevel@tonic-gate return (sp); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate if (fmd_scheme_rtld_init(sp) != 0) { 1717c478bd9Sstevel@tonic-gate sp->sch_err = errno; 1727c478bd9Sstevel@tonic-gate (void) dlclose(sp->sch_dlp); 1737c478bd9Sstevel@tonic-gate sp->sch_dlp = NULL; 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate return (sp); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate char * 1807c478bd9Sstevel@tonic-gate fmdump_nvl2str(nvlist_t *nvl) 1817c478bd9Sstevel@tonic-gate { 1827c478bd9Sstevel@tonic-gate fmd_scheme_t *sp; 1837c478bd9Sstevel@tonic-gate char c, *name, *s = NULL; 1847c478bd9Sstevel@tonic-gate ssize_t len; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) { 1877c478bd9Sstevel@tonic-gate fmdump_warn("fmri does not contain required '%s' nvpair\n", 1887c478bd9Sstevel@tonic-gate FM_FMRI_SCHEME); 1897c478bd9Sstevel@tonic-gate return (NULL); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate if ((sp = fmd_scheme_lookup("/usr/lib/fm/fmd/schemes", name)) == NULL || 1937c478bd9Sstevel@tonic-gate sp->sch_dlp == NULL || sp->sch_err != 0) { 1947c478bd9Sstevel@tonic-gate const char *msg = 1957c478bd9Sstevel@tonic-gate sp->sch_err == ELIBACC ? dlerror() : strerror(sp->sch_err); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate fmdump_warn("cannot init '%s' scheme library to " 1987c478bd9Sstevel@tonic-gate "format fmri: %s\n", name, msg ? msg : "unknown error"); 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate return (NULL); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if ((len = sp->sch_ops.sop_nvl2str(nvl, &c, sizeof (c))) == -1 || 2047c478bd9Sstevel@tonic-gate (s = malloc(len + 1)) == NULL || 2057c478bd9Sstevel@tonic-gate sp->sch_ops.sop_nvl2str(nvl, s, len + 1) == -1) { 2067c478bd9Sstevel@tonic-gate fmdump_warn("cannot format fmri using scheme '%s'", name); 2077c478bd9Sstevel@tonic-gate free(s); 2087c478bd9Sstevel@tonic-gate return (NULL); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate return (s); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate void * 2167c478bd9Sstevel@tonic-gate fmd_fmri_alloc(size_t size) 2177c478bd9Sstevel@tonic-gate { 2187c478bd9Sstevel@tonic-gate return (malloc(size)); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate void * 2227c478bd9Sstevel@tonic-gate fmd_fmri_zalloc(size_t size) 2237c478bd9Sstevel@tonic-gate { 2247c478bd9Sstevel@tonic-gate void *data; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate if ((data = malloc(size)) != NULL) 2277c478bd9Sstevel@tonic-gate bzero(data, size); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate return (data); 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2337c478bd9Sstevel@tonic-gate void 2347c478bd9Sstevel@tonic-gate fmd_fmri_free(void *data, size_t size) 2357c478bd9Sstevel@tonic-gate { 2367c478bd9Sstevel@tonic-gate free(data); 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate int 2407c478bd9Sstevel@tonic-gate fmd_fmri_error(int err) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate errno = err; 2437c478bd9Sstevel@tonic-gate return (-1); 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate char * 2477c478bd9Sstevel@tonic-gate fmd_fmri_strescape(const char *s) 2487c478bd9Sstevel@tonic-gate { 2497c478bd9Sstevel@tonic-gate return (strdup(s)); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate char * 2537c478bd9Sstevel@tonic-gate fmd_fmri_strdup(const char *s) 2547c478bd9Sstevel@tonic-gate { 2557c478bd9Sstevel@tonic-gate return (strdup(s)); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate void 2597c478bd9Sstevel@tonic-gate fmd_fmri_strfree(char *s) 2607c478bd9Sstevel@tonic-gate { 2617c478bd9Sstevel@tonic-gate free(s); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate const char * 2657c478bd9Sstevel@tonic-gate fmd_fmri_get_rootdir(void) 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate return (g_root ? g_root : ""); 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate const char * 2717c478bd9Sstevel@tonic-gate fmd_fmri_get_platform(void) 2727c478bd9Sstevel@tonic-gate { 2737c478bd9Sstevel@tonic-gate static char platform[MAXNAMELEN]; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate if (platform[0] == '\0') 2767c478bd9Sstevel@tonic-gate (void) sysinfo(SI_PLATFORM, platform, sizeof (platform)); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate return (platform); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate uint64_t 2827c478bd9Sstevel@tonic-gate fmd_fmri_get_drgen(void) 2837c478bd9Sstevel@tonic-gate { 2847c478bd9Sstevel@tonic-gate return (0); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate int 2887c478bd9Sstevel@tonic-gate fmd_fmri_set_errno(int err) 2897c478bd9Sstevel@tonic-gate { 2907c478bd9Sstevel@tonic-gate errno = err; 2917c478bd9Sstevel@tonic-gate return (-1); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate void 2957c478bd9Sstevel@tonic-gate fmd_fmri_warn(const char *format, ...) 2967c478bd9Sstevel@tonic-gate { 2977c478bd9Sstevel@tonic-gate va_list ap; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate va_start(ap, format); 3007c478bd9Sstevel@tonic-gate fmdump_vwarn(format, ap); 3017c478bd9Sstevel@tonic-gate va_end(ap); 3027c478bd9Sstevel@tonic-gate } 3037aec1d6eScindi 3047aec1d6eScindi struct topo_hdl * 305*24db4641Seschrock fmd_fmri_topo_hold(int version) 3067aec1d6eScindi { 3077aec1d6eScindi int err; 3087aec1d6eScindi 309*24db4641Seschrock if (version != TOPO_VERSION) 310*24db4641Seschrock return (NULL); 311*24db4641Seschrock 3127aec1d6eScindi if (g_thp == NULL) { 3137aec1d6eScindi if ((g_thp = topo_open(TOPO_VERSION, "/", &err)) == NULL) { 3147aec1d6eScindi (void) fprintf(stderr, "topo_open failed: %s\n", 3157aec1d6eScindi topo_strerror(err)); 3167aec1d6eScindi exit(1); 3177aec1d6eScindi } 3187aec1d6eScindi } 3197aec1d6eScindi 3207aec1d6eScindi return (g_thp); 3217aec1d6eScindi } 322*24db4641Seschrock 323*24db4641Seschrock /*ARGSUSED*/ 324*24db4641Seschrock void 325*24db4641Seschrock fmd_fmri_topo_rele(struct topo_hdl *thp) 326*24db4641Seschrock { 327*24db4641Seschrock /* nothing to do */ 328*24db4641Seschrock } 329