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