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