xref: /onnv-gate/usr/src/cmd/fm/fmdump/common/scheme.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/systeminfo.h>
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include <limits.h>
33*0Sstevel@tonic-gate #include <strings.h>
34*0Sstevel@tonic-gate #include <stddef.h>
35*0Sstevel@tonic-gate #include <unistd.h>
36*0Sstevel@tonic-gate #include <dlfcn.h>
37*0Sstevel@tonic-gate #include <errno.h>
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #include <fmdump.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate  * fmdump loadable scheme support
43*0Sstevel@tonic-gate  *
44*0Sstevel@tonic-gate  * This file provides a pared-down implementation of fmd's fmd_fmri.c and
45*0Sstevel@tonic-gate  * fmd_scheme.c and must be kept in sync with the set of service routines
46*0Sstevel@tonic-gate  * required by scheme plug-ins.  At some point if other utilities want to
47*0Sstevel@tonic-gate  * use this we can refactor it into a more general library.  (Note: fmd
48*0Sstevel@tonic-gate  * cannot use such a library because it has its own internal locking, etc.)
49*0Sstevel@tonic-gate  * As schemes are needed, we dlopen() them and cache a list of them which we
50*0Sstevel@tonic-gate  * can search later.  We also use the list as a negative cache: if we fail to
51*0Sstevel@tonic-gate  * load a scheme, we add an entry with sch_dlp = NULL and sch_err recording
52*0Sstevel@tonic-gate  * the errno to be returned to the caller.
53*0Sstevel@tonic-gate  */
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate typedef struct fmd_scheme_ops {
56*0Sstevel@tonic-gate 	int (*sop_init)(void);
57*0Sstevel@tonic-gate 	void (*sop_fini)(void);
58*0Sstevel@tonic-gate 	ssize_t (*sop_nvl2str)(nvlist_t *, char *, size_t);
59*0Sstevel@tonic-gate } fmd_scheme_ops_t;
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate typedef struct fmd_scheme_opd {
62*0Sstevel@tonic-gate 	const char *opd_name;		/* symbol name of scheme function */
63*0Sstevel@tonic-gate 	size_t opd_off;			/* offset within fmd_scheme_ops_t */
64*0Sstevel@tonic-gate } fmd_scheme_opd_t;
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate typedef struct fmd_scheme {
67*0Sstevel@tonic-gate 	struct fmd_scheme *sch_next;    /* next scheme on list of schemes */
68*0Sstevel@tonic-gate 	char *sch_name;			/* name of this scheme (fmri prefix) */
69*0Sstevel@tonic-gate 	void *sch_dlp;			/* libdl(3DL) shared library handle */
70*0Sstevel@tonic-gate 	int sch_err;			/* if negative entry, errno to return */
71*0Sstevel@tonic-gate 	fmd_scheme_ops_t sch_ops;	/* scheme function pointers */
72*0Sstevel@tonic-gate } fmd_scheme_t;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate static fmd_scheme_t *sch_list;		/* list of cached schemes */
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate static long
77*0Sstevel@tonic-gate fmd_scheme_notsup(void)
78*0Sstevel@tonic-gate {
79*0Sstevel@tonic-gate 	errno = ENOTSUP;
80*0Sstevel@tonic-gate 	return (-1);
81*0Sstevel@tonic-gate }
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate static int
84*0Sstevel@tonic-gate fmd_scheme_nop(void)
85*0Sstevel@tonic-gate {
86*0Sstevel@tonic-gate 	return (0);
87*0Sstevel@tonic-gate }
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate /*
90*0Sstevel@tonic-gate  * Default values for the scheme ops.  If a scheme function is not defined in
91*0Sstevel@tonic-gate  * the module, then this operation is implemented using the default function.
92*0Sstevel@tonic-gate  */
93*0Sstevel@tonic-gate static const fmd_scheme_ops_t _fmd_scheme_default_ops = {
94*0Sstevel@tonic-gate 	(int (*)())fmd_scheme_nop,		/* sop_init */
95*0Sstevel@tonic-gate 	(void (*)())fmd_scheme_nop,		/* sop_fini */
96*0Sstevel@tonic-gate 	(ssize_t (*)())fmd_scheme_notsup,	/* sop_nvl2str */
97*0Sstevel@tonic-gate };
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * Scheme ops descriptions.  These names and offsets are used by the function
101*0Sstevel@tonic-gate  * fmd_scheme_rtld_init(), defined below, to load up a fmd_scheme_ops_t.
102*0Sstevel@tonic-gate  */
103*0Sstevel@tonic-gate static const fmd_scheme_opd_t _fmd_scheme_ops[] = {
104*0Sstevel@tonic-gate 	{ "fmd_fmri_init", offsetof(fmd_scheme_ops_t, sop_init) },
105*0Sstevel@tonic-gate 	{ "fmd_fmri_fini", offsetof(fmd_scheme_ops_t, sop_fini) },
106*0Sstevel@tonic-gate 	{ "fmd_fmri_nvl2str", offsetof(fmd_scheme_ops_t, sop_nvl2str) },
107*0Sstevel@tonic-gate 	{ NULL, 0 }
108*0Sstevel@tonic-gate };
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate static fmd_scheme_t *
111*0Sstevel@tonic-gate fmd_scheme_create(const char *name)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	fmd_scheme_t *sp;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	if ((sp = malloc(sizeof (fmd_scheme_t))) == NULL ||
116*0Sstevel@tonic-gate 	    (sp->sch_name = strdup(name)) == NULL) {
117*0Sstevel@tonic-gate 		free(sp);
118*0Sstevel@tonic-gate 		return (NULL);
119*0Sstevel@tonic-gate 	}
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 	sp->sch_next = sch_list;
122*0Sstevel@tonic-gate 	sp->sch_dlp = NULL;
123*0Sstevel@tonic-gate 	sp->sch_err = 0;
124*0Sstevel@tonic-gate 	sp->sch_ops = _fmd_scheme_default_ops;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	sch_list = sp;
127*0Sstevel@tonic-gate 	return (sp);
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate static int
131*0Sstevel@tonic-gate fmd_scheme_rtld_init(fmd_scheme_t *sp)
132*0Sstevel@tonic-gate {
133*0Sstevel@tonic-gate 	const fmd_scheme_opd_t *opd;
134*0Sstevel@tonic-gate 	void *p;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	for (opd = _fmd_scheme_ops; opd->opd_name != NULL; opd++) {
137*0Sstevel@tonic-gate 		if ((p = dlsym(sp->sch_dlp, opd->opd_name)) != NULL)
138*0Sstevel@tonic-gate 			*(void **)((uintptr_t)&sp->sch_ops + opd->opd_off) = p;
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	return (sp->sch_ops.sop_init());
142*0Sstevel@tonic-gate }
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate static fmd_scheme_t *
145*0Sstevel@tonic-gate fmd_scheme_lookup(const char *dir, const char *name)
146*0Sstevel@tonic-gate {
147*0Sstevel@tonic-gate 	fmd_scheme_t *sp;
148*0Sstevel@tonic-gate 	char path[PATH_MAX];
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	for (sp = sch_list; sp != NULL; sp = sp->sch_next) {
151*0Sstevel@tonic-gate 		if (strcmp(name, sp->sch_name) == 0)
152*0Sstevel@tonic-gate 			return (sp);
153*0Sstevel@tonic-gate 	}
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 	if ((sp = fmd_scheme_create(name)) == NULL)
156*0Sstevel@tonic-gate 		return (NULL); /* errno is set for us */
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s/%s.so",
159*0Sstevel@tonic-gate 	    g_root ? g_root : "", dir, name);
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	if (access(path, F_OK) != 0) {
162*0Sstevel@tonic-gate 		sp->sch_err = errno;
163*0Sstevel@tonic-gate 		return (sp);
164*0Sstevel@tonic-gate 	}
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	if ((sp->sch_dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW)) == NULL) {
167*0Sstevel@tonic-gate 		sp->sch_err = ELIBACC;
168*0Sstevel@tonic-gate 		return (sp);
169*0Sstevel@tonic-gate 	}
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	if (fmd_scheme_rtld_init(sp) != 0) {
172*0Sstevel@tonic-gate 		sp->sch_err = errno;
173*0Sstevel@tonic-gate 		(void) dlclose(sp->sch_dlp);
174*0Sstevel@tonic-gate 		sp->sch_dlp = NULL;
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	return (sp);
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate char *
181*0Sstevel@tonic-gate fmdump_nvl2str(nvlist_t *nvl)
182*0Sstevel@tonic-gate {
183*0Sstevel@tonic-gate 	fmd_scheme_t *sp;
184*0Sstevel@tonic-gate 	char c, *name, *s = NULL;
185*0Sstevel@tonic-gate 	ssize_t len;
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) {
188*0Sstevel@tonic-gate 		fmdump_warn("fmri does not contain required '%s' nvpair\n",
189*0Sstevel@tonic-gate 		    FM_FMRI_SCHEME);
190*0Sstevel@tonic-gate 		return (NULL);
191*0Sstevel@tonic-gate 	}
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if ((sp = fmd_scheme_lookup("/usr/lib/fm/fmd/schemes", name)) == NULL ||
194*0Sstevel@tonic-gate 	    sp->sch_dlp == NULL || sp->sch_err != 0) {
195*0Sstevel@tonic-gate 		const char *msg =
196*0Sstevel@tonic-gate 		    sp->sch_err == ELIBACC ? dlerror() : strerror(sp->sch_err);
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 		fmdump_warn("cannot init '%s' scheme library to "
199*0Sstevel@tonic-gate 		    "format fmri: %s\n", name, msg ? msg : "unknown error");
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 		return (NULL);
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	if ((len = sp->sch_ops.sop_nvl2str(nvl, &c, sizeof (c))) == -1 ||
205*0Sstevel@tonic-gate 	    (s = malloc(len + 1)) == NULL ||
206*0Sstevel@tonic-gate 	    sp->sch_ops.sop_nvl2str(nvl, s, len + 1) == -1) {
207*0Sstevel@tonic-gate 		fmdump_warn("cannot format fmri using scheme '%s'", name);
208*0Sstevel@tonic-gate 		free(s);
209*0Sstevel@tonic-gate 		return (NULL);
210*0Sstevel@tonic-gate 	}
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	return (s);
213*0Sstevel@tonic-gate }
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate void *
217*0Sstevel@tonic-gate fmd_fmri_alloc(size_t size)
218*0Sstevel@tonic-gate {
219*0Sstevel@tonic-gate 	return (malloc(size));
220*0Sstevel@tonic-gate }
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate void *
223*0Sstevel@tonic-gate fmd_fmri_zalloc(size_t size)
224*0Sstevel@tonic-gate {
225*0Sstevel@tonic-gate 	void *data;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	if ((data = malloc(size)) != NULL)
228*0Sstevel@tonic-gate 		bzero(data, size);
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	return (data);
231*0Sstevel@tonic-gate }
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate /*ARGSUSED*/
234*0Sstevel@tonic-gate void
235*0Sstevel@tonic-gate fmd_fmri_free(void *data, size_t size)
236*0Sstevel@tonic-gate {
237*0Sstevel@tonic-gate 	free(data);
238*0Sstevel@tonic-gate }
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate int
241*0Sstevel@tonic-gate fmd_fmri_error(int err)
242*0Sstevel@tonic-gate {
243*0Sstevel@tonic-gate 	errno = err;
244*0Sstevel@tonic-gate 	return (-1);
245*0Sstevel@tonic-gate }
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate char *
248*0Sstevel@tonic-gate fmd_fmri_strescape(const char *s)
249*0Sstevel@tonic-gate {
250*0Sstevel@tonic-gate 	return (strdup(s));
251*0Sstevel@tonic-gate }
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate char *
254*0Sstevel@tonic-gate fmd_fmri_strdup(const char *s)
255*0Sstevel@tonic-gate {
256*0Sstevel@tonic-gate 	return (strdup(s));
257*0Sstevel@tonic-gate }
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate void
260*0Sstevel@tonic-gate fmd_fmri_strfree(char *s)
261*0Sstevel@tonic-gate {
262*0Sstevel@tonic-gate 	free(s);
263*0Sstevel@tonic-gate }
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate const char *
266*0Sstevel@tonic-gate fmd_fmri_get_rootdir(void)
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate 	return (g_root ? g_root : "");
269*0Sstevel@tonic-gate }
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate const char *
272*0Sstevel@tonic-gate fmd_fmri_get_platform(void)
273*0Sstevel@tonic-gate {
274*0Sstevel@tonic-gate 	static char platform[MAXNAMELEN];
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	if (platform[0] == '\0')
277*0Sstevel@tonic-gate 		(void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	return (platform);
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate uint64_t
283*0Sstevel@tonic-gate fmd_fmri_get_drgen(void)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	return (0);
286*0Sstevel@tonic-gate }
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate int
289*0Sstevel@tonic-gate fmd_fmri_set_errno(int err)
290*0Sstevel@tonic-gate {
291*0Sstevel@tonic-gate 	errno = err;
292*0Sstevel@tonic-gate 	return (-1);
293*0Sstevel@tonic-gate }
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate void
296*0Sstevel@tonic-gate fmd_fmri_warn(const char *format, ...)
297*0Sstevel@tonic-gate {
298*0Sstevel@tonic-gate 	va_list ap;
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	va_start(ap, format);
301*0Sstevel@tonic-gate 	fmdump_vwarn(format, ap);
302*0Sstevel@tonic-gate 	va_end(ap);
303*0Sstevel@tonic-gate }
304