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