xref: /onnv-gate/usr/src/cmd/fm/fmdump/common/scheme.c (revision 4198:6bdfb19526db)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*4198Seschrock  * Common Development and Distribution License (the "License").
6*4198Seschrock  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*4198Seschrock  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/systeminfo.h>
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <limits.h>
320Sstevel@tonic-gate #include <strings.h>
330Sstevel@tonic-gate #include <stddef.h>
340Sstevel@tonic-gate #include <unistd.h>
350Sstevel@tonic-gate #include <dlfcn.h>
360Sstevel@tonic-gate #include <errno.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <fmdump.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate  * fmdump loadable scheme support
420Sstevel@tonic-gate  *
430Sstevel@tonic-gate  * This file provides a pared-down implementation of fmd's fmd_fmri.c and
440Sstevel@tonic-gate  * fmd_scheme.c and must be kept in sync with the set of service routines
450Sstevel@tonic-gate  * required by scheme plug-ins.  At some point if other utilities want to
460Sstevel@tonic-gate  * use this we can refactor it into a more general library.  (Note: fmd
470Sstevel@tonic-gate  * cannot use such a library because it has its own internal locking, etc.)
480Sstevel@tonic-gate  * As schemes are needed, we dlopen() them and cache a list of them which we
490Sstevel@tonic-gate  * can search later.  We also use the list as a negative cache: if we fail to
500Sstevel@tonic-gate  * load a scheme, we add an entry with sch_dlp = NULL and sch_err recording
510Sstevel@tonic-gate  * the errno to be returned to the caller.
520Sstevel@tonic-gate  */
530Sstevel@tonic-gate 
540Sstevel@tonic-gate typedef struct fmd_scheme_ops {
550Sstevel@tonic-gate 	int (*sop_init)(void);
560Sstevel@tonic-gate 	void (*sop_fini)(void);
570Sstevel@tonic-gate 	ssize_t (*sop_nvl2str)(nvlist_t *, char *, size_t);
580Sstevel@tonic-gate } fmd_scheme_ops_t;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate typedef struct fmd_scheme_opd {
610Sstevel@tonic-gate 	const char *opd_name;		/* symbol name of scheme function */
620Sstevel@tonic-gate 	size_t opd_off;			/* offset within fmd_scheme_ops_t */
630Sstevel@tonic-gate } fmd_scheme_opd_t;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate typedef struct fmd_scheme {
660Sstevel@tonic-gate 	struct fmd_scheme *sch_next;    /* next scheme on list of schemes */
670Sstevel@tonic-gate 	char *sch_name;			/* name of this scheme (fmri prefix) */
680Sstevel@tonic-gate 	void *sch_dlp;			/* libdl(3DL) shared library handle */
690Sstevel@tonic-gate 	int sch_err;			/* if negative entry, errno to return */
700Sstevel@tonic-gate 	fmd_scheme_ops_t sch_ops;	/* scheme function pointers */
710Sstevel@tonic-gate } fmd_scheme_t;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate static fmd_scheme_t *sch_list;		/* list of cached schemes */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate static long
fmd_scheme_notsup(void)760Sstevel@tonic-gate fmd_scheme_notsup(void)
770Sstevel@tonic-gate {
780Sstevel@tonic-gate 	errno = ENOTSUP;
790Sstevel@tonic-gate 	return (-1);
800Sstevel@tonic-gate }
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static int
fmd_scheme_nop(void)830Sstevel@tonic-gate fmd_scheme_nop(void)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate 	return (0);
860Sstevel@tonic-gate }
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate  * Default values for the scheme ops.  If a scheme function is not defined in
900Sstevel@tonic-gate  * the module, then this operation is implemented using the default function.
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate static const fmd_scheme_ops_t _fmd_scheme_default_ops = {
930Sstevel@tonic-gate 	(int (*)())fmd_scheme_nop,		/* sop_init */
940Sstevel@tonic-gate 	(void (*)())fmd_scheme_nop,		/* sop_fini */
950Sstevel@tonic-gate 	(ssize_t (*)())fmd_scheme_notsup,	/* sop_nvl2str */
960Sstevel@tonic-gate };
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * Scheme ops descriptions.  These names and offsets are used by the function
1000Sstevel@tonic-gate  * fmd_scheme_rtld_init(), defined below, to load up a fmd_scheme_ops_t.
1010Sstevel@tonic-gate  */
1020Sstevel@tonic-gate static const fmd_scheme_opd_t _fmd_scheme_ops[] = {
1030Sstevel@tonic-gate 	{ "fmd_fmri_init", offsetof(fmd_scheme_ops_t, sop_init) },
1040Sstevel@tonic-gate 	{ "fmd_fmri_fini", offsetof(fmd_scheme_ops_t, sop_fini) },
1050Sstevel@tonic-gate 	{ "fmd_fmri_nvl2str", offsetof(fmd_scheme_ops_t, sop_nvl2str) },
1060Sstevel@tonic-gate 	{ NULL, 0 }
1070Sstevel@tonic-gate };
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate static fmd_scheme_t *
fmd_scheme_create(const char * name)1100Sstevel@tonic-gate fmd_scheme_create(const char *name)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	fmd_scheme_t *sp;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	if ((sp = malloc(sizeof (fmd_scheme_t))) == NULL ||
1150Sstevel@tonic-gate 	    (sp->sch_name = strdup(name)) == NULL) {
1160Sstevel@tonic-gate 		free(sp);
1170Sstevel@tonic-gate 		return (NULL);
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	sp->sch_next = sch_list;
1210Sstevel@tonic-gate 	sp->sch_dlp = NULL;
1220Sstevel@tonic-gate 	sp->sch_err = 0;
1230Sstevel@tonic-gate 	sp->sch_ops = _fmd_scheme_default_ops;
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	sch_list = sp;
1260Sstevel@tonic-gate 	return (sp);
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static int
fmd_scheme_rtld_init(fmd_scheme_t * sp)1300Sstevel@tonic-gate fmd_scheme_rtld_init(fmd_scheme_t *sp)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate 	const fmd_scheme_opd_t *opd;
1330Sstevel@tonic-gate 	void *p;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	for (opd = _fmd_scheme_ops; opd->opd_name != NULL; opd++) {
1360Sstevel@tonic-gate 		if ((p = dlsym(sp->sch_dlp, opd->opd_name)) != NULL)
1370Sstevel@tonic-gate 			*(void **)((uintptr_t)&sp->sch_ops + opd->opd_off) = p;
1380Sstevel@tonic-gate 	}
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	return (sp->sch_ops.sop_init());
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate static fmd_scheme_t *
fmd_scheme_lookup(const char * dir,const char * name)1440Sstevel@tonic-gate fmd_scheme_lookup(const char *dir, const char *name)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate 	fmd_scheme_t *sp;
1470Sstevel@tonic-gate 	char path[PATH_MAX];
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	for (sp = sch_list; sp != NULL; sp = sp->sch_next) {
1500Sstevel@tonic-gate 		if (strcmp(name, sp->sch_name) == 0)
1510Sstevel@tonic-gate 			return (sp);
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	if ((sp = fmd_scheme_create(name)) == NULL)
1550Sstevel@tonic-gate 		return (NULL); /* errno is set for us */
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s/%s.so",
1580Sstevel@tonic-gate 	    g_root ? g_root : "", dir, name);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	if (access(path, F_OK) != 0) {
1610Sstevel@tonic-gate 		sp->sch_err = errno;
1620Sstevel@tonic-gate 		return (sp);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	if ((sp->sch_dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW)) == NULL) {
1660Sstevel@tonic-gate 		sp->sch_err = ELIBACC;
1670Sstevel@tonic-gate 		return (sp);
1680Sstevel@tonic-gate 	}
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	if (fmd_scheme_rtld_init(sp) != 0) {
1710Sstevel@tonic-gate 		sp->sch_err = errno;
1720Sstevel@tonic-gate 		(void) dlclose(sp->sch_dlp);
1730Sstevel@tonic-gate 		sp->sch_dlp = NULL;
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	return (sp);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate char *
fmdump_nvl2str(nvlist_t * nvl)1800Sstevel@tonic-gate fmdump_nvl2str(nvlist_t *nvl)
1810Sstevel@tonic-gate {
1820Sstevel@tonic-gate 	fmd_scheme_t *sp;
1830Sstevel@tonic-gate 	char c, *name, *s = NULL;
1840Sstevel@tonic-gate 	ssize_t len;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) {
1870Sstevel@tonic-gate 		fmdump_warn("fmri does not contain required '%s' nvpair\n",
1880Sstevel@tonic-gate 		    FM_FMRI_SCHEME);
1890Sstevel@tonic-gate 		return (NULL);
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if ((sp = fmd_scheme_lookup("/usr/lib/fm/fmd/schemes", name)) == NULL ||
1930Sstevel@tonic-gate 	    sp->sch_dlp == NULL || sp->sch_err != 0) {
1940Sstevel@tonic-gate 		const char *msg =
1950Sstevel@tonic-gate 		    sp->sch_err == ELIBACC ? dlerror() : strerror(sp->sch_err);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 		fmdump_warn("cannot init '%s' scheme library to "
1980Sstevel@tonic-gate 		    "format fmri: %s\n", name, msg ? msg : "unknown error");
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 		return (NULL);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if ((len = sp->sch_ops.sop_nvl2str(nvl, &c, sizeof (c))) == -1 ||
2040Sstevel@tonic-gate 	    (s = malloc(len + 1)) == NULL ||
2050Sstevel@tonic-gate 	    sp->sch_ops.sop_nvl2str(nvl, s, len + 1) == -1) {
2060Sstevel@tonic-gate 		fmdump_warn("cannot format fmri using scheme '%s'", name);
2070Sstevel@tonic-gate 		free(s);
2080Sstevel@tonic-gate 		return (NULL);
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	return (s);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate void *
fmd_fmri_alloc(size_t size)2160Sstevel@tonic-gate fmd_fmri_alloc(size_t size)
2170Sstevel@tonic-gate {
2180Sstevel@tonic-gate 	return (malloc(size));
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate void *
fmd_fmri_zalloc(size_t size)2220Sstevel@tonic-gate fmd_fmri_zalloc(size_t size)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	void *data;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	if ((data = malloc(size)) != NULL)
2270Sstevel@tonic-gate 		bzero(data, size);
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	return (data);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*ARGSUSED*/
2330Sstevel@tonic-gate void
fmd_fmri_free(void * data,size_t size)2340Sstevel@tonic-gate fmd_fmri_free(void *data, size_t size)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	free(data);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate int
fmd_fmri_error(int err)2400Sstevel@tonic-gate fmd_fmri_error(int err)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate 	errno = err;
2430Sstevel@tonic-gate 	return (-1);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate char *
fmd_fmri_strescape(const char * s)2470Sstevel@tonic-gate fmd_fmri_strescape(const char *s)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate 	return (strdup(s));
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate char *
fmd_fmri_strdup(const char * s)2530Sstevel@tonic-gate fmd_fmri_strdup(const char *s)
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	return (strdup(s));
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate void
fmd_fmri_strfree(char * s)2590Sstevel@tonic-gate fmd_fmri_strfree(char *s)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate 	free(s);
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate const char *
fmd_fmri_get_rootdir(void)2650Sstevel@tonic-gate fmd_fmri_get_rootdir(void)
2660Sstevel@tonic-gate {
2670Sstevel@tonic-gate 	return (g_root ? g_root : "");
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate const char *
fmd_fmri_get_platform(void)2710Sstevel@tonic-gate fmd_fmri_get_platform(void)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	static char platform[MAXNAMELEN];
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if (platform[0] == '\0')
2760Sstevel@tonic-gate 		(void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	return (platform);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate uint64_t
fmd_fmri_get_drgen(void)2820Sstevel@tonic-gate fmd_fmri_get_drgen(void)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	return (0);
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate int
fmd_fmri_set_errno(int err)2880Sstevel@tonic-gate fmd_fmri_set_errno(int err)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate 	errno = err;
2910Sstevel@tonic-gate 	return (-1);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate void
fmd_fmri_warn(const char * format,...)2950Sstevel@tonic-gate fmd_fmri_warn(const char *format, ...)
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate 	va_list ap;
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	va_start(ap, format);
3000Sstevel@tonic-gate 	fmdump_vwarn(format, ap);
3010Sstevel@tonic-gate 	va_end(ap);
3020Sstevel@tonic-gate }
3031414Scindi 
3041414Scindi struct topo_hdl *
fmd_fmri_topo_hold(int version)305*4198Seschrock fmd_fmri_topo_hold(int version)
3061414Scindi {
3071414Scindi 	int err;
3081414Scindi 
309*4198Seschrock 	if (version != TOPO_VERSION)
310*4198Seschrock 		return (NULL);
311*4198Seschrock 
3121414Scindi 	if (g_thp == NULL) {
3131414Scindi 		if ((g_thp = topo_open(TOPO_VERSION, "/", &err)) == NULL) {
3141414Scindi 			(void) fprintf(stderr, "topo_open failed: %s\n",
3151414Scindi 			    topo_strerror(err));
3161414Scindi 			exit(1);
3171414Scindi 		}
3181414Scindi 	}
3191414Scindi 
3201414Scindi 	return (g_thp);
3211414Scindi }
322*4198Seschrock 
323*4198Seschrock /*ARGSUSED*/
324*4198Seschrock void
fmd_fmri_topo_rele(struct topo_hdl * thp)325*4198Seschrock fmd_fmri_topo_rele(struct topo_hdl *thp)
326*4198Seschrock {
327*4198Seschrock 	/* nothing to do */
328*4198Seschrock }
329