dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fm / fmdump / common / scheme.c
blob425fbd302cbbf2b1cece068c29205efbba137db3
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/types.h>
29 #include <sys/systeminfo.h>
31 #include <limits.h>
32 #include <strings.h>
33 #include <stddef.h>
34 #include <unistd.h>
35 #include <dlfcn.h>
36 #include <errno.h>
38 #include <fmdump.h>
41 * fmdump loadable scheme support
43 * This file provides a pared-down implementation of fmd's fmd_fmri.c and
44 * fmd_scheme.c and must be kept in sync with the set of service routines
45 * required by scheme plug-ins. At some point if other utilities want to
46 * use this we can refactor it into a more general library. (Note: fmd
47 * cannot use such a library because it has its own internal locking, etc.)
48 * As schemes are needed, we dlopen() them and cache a list of them which we
49 * can search later. We also use the list as a negative cache: if we fail to
50 * load a scheme, we add an entry with sch_dlp = NULL and sch_err recording
51 * the errno to be returned to the caller.
54 typedef struct fmd_scheme_ops {
55 int (*sop_init)(void);
56 void (*sop_fini)(void);
57 ssize_t (*sop_nvl2str)(nvlist_t *, char *, size_t);
58 } fmd_scheme_ops_t;
60 typedef struct fmd_scheme_opd {
61 const char *opd_name; /* symbol name of scheme function */
62 size_t opd_off; /* offset within fmd_scheme_ops_t */
63 } fmd_scheme_opd_t;
65 typedef struct fmd_scheme {
66 struct fmd_scheme *sch_next; /* next scheme on list of schemes */
67 char *sch_name; /* name of this scheme (fmri prefix) */
68 void *sch_dlp; /* libdl(3DL) shared library handle */
69 int sch_err; /* if negative entry, errno to return */
70 fmd_scheme_ops_t sch_ops; /* scheme function pointers */
71 } fmd_scheme_t;
73 static fmd_scheme_t *sch_list; /* list of cached schemes */
75 static long
76 fmd_scheme_notsup(void)
78 errno = ENOTSUP;
79 return (-1);
82 static int
83 fmd_scheme_nop(void)
85 return (0);
89 * Default values for the scheme ops. If a scheme function is not defined in
90 * the module, then this operation is implemented using the default function.
92 static const fmd_scheme_ops_t _fmd_scheme_default_ops = {
93 (int (*)())fmd_scheme_nop, /* sop_init */
94 (void (*)())fmd_scheme_nop, /* sop_fini */
95 (ssize_t (*)())fmd_scheme_notsup, /* sop_nvl2str */
99 * Scheme ops descriptions. These names and offsets are used by the function
100 * fmd_scheme_rtld_init(), defined below, to load up a fmd_scheme_ops_t.
102 static const fmd_scheme_opd_t _fmd_scheme_ops[] = {
103 { "fmd_fmri_init", offsetof(fmd_scheme_ops_t, sop_init) },
104 { "fmd_fmri_fini", offsetof(fmd_scheme_ops_t, sop_fini) },
105 { "fmd_fmri_nvl2str", offsetof(fmd_scheme_ops_t, sop_nvl2str) },
106 { NULL, 0 }
109 static fmd_scheme_t *
110 fmd_scheme_create(const char *name)
112 fmd_scheme_t *sp;
114 if ((sp = malloc(sizeof (fmd_scheme_t))) == NULL ||
115 (sp->sch_name = strdup(name)) == NULL) {
116 free(sp);
117 return (NULL);
120 sp->sch_next = sch_list;
121 sp->sch_dlp = NULL;
122 sp->sch_err = 0;
123 sp->sch_ops = _fmd_scheme_default_ops;
125 sch_list = sp;
126 return (sp);
129 static int
130 fmd_scheme_rtld_init(fmd_scheme_t *sp)
132 const fmd_scheme_opd_t *opd;
133 void *p;
135 for (opd = _fmd_scheme_ops; opd->opd_name != NULL; opd++) {
136 if ((p = dlsym(sp->sch_dlp, opd->opd_name)) != NULL)
137 *(void **)((uintptr_t)&sp->sch_ops + opd->opd_off) = p;
140 return (sp->sch_ops.sop_init());
143 static fmd_scheme_t *
144 fmd_scheme_lookup(const char *dir, const char *name)
146 fmd_scheme_t *sp;
147 char path[PATH_MAX];
149 for (sp = sch_list; sp != NULL; sp = sp->sch_next) {
150 if (strcmp(name, sp->sch_name) == 0)
151 return (sp);
154 if ((sp = fmd_scheme_create(name)) == NULL)
155 return (NULL); /* errno is set for us */
157 (void) snprintf(path, sizeof (path), "%s%s/%s.so",
158 g_root ? g_root : "", dir, name);
160 if (access(path, F_OK) != 0) {
161 sp->sch_err = errno;
162 return (sp);
165 if ((sp->sch_dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW)) == NULL) {
166 sp->sch_err = ELIBACC;
167 return (sp);
170 if (fmd_scheme_rtld_init(sp) != 0) {
171 sp->sch_err = errno;
172 (void) dlclose(sp->sch_dlp);
173 sp->sch_dlp = NULL;
176 return (sp);
179 char *
180 fmdump_nvl2str(nvlist_t *nvl)
182 fmd_scheme_t *sp;
183 char c, *name, *s = NULL;
184 ssize_t len;
186 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) {
187 fmdump_warn("fmri does not contain required '%s' nvpair\n",
188 FM_FMRI_SCHEME);
189 return (NULL);
192 if ((sp = fmd_scheme_lookup("/usr/lib/fm/fmd/schemes", name)) == NULL ||
193 sp->sch_dlp == NULL || sp->sch_err != 0) {
194 const char *msg =
195 sp->sch_err == ELIBACC ? dlerror() : strerror(sp->sch_err);
197 fmdump_warn("cannot init '%s' scheme library to "
198 "format fmri: %s\n", name, msg ? msg : "unknown error");
200 return (NULL);
203 if ((len = sp->sch_ops.sop_nvl2str(nvl, &c, sizeof (c))) == -1 ||
204 (s = malloc(len + 1)) == NULL ||
205 sp->sch_ops.sop_nvl2str(nvl, s, len + 1) == -1) {
206 fmdump_warn("cannot format fmri using scheme '%s'", name);
207 free(s);
208 return (NULL);
211 return (s);
215 void *
216 fmd_fmri_alloc(size_t size)
218 return (malloc(size));
221 void *
222 fmd_fmri_zalloc(size_t size)
224 void *data;
226 if ((data = malloc(size)) != NULL)
227 bzero(data, size);
229 return (data);
232 /*ARGSUSED*/
233 void
234 fmd_fmri_free(void *data, size_t size)
236 free(data);
240 fmd_fmri_error(int err)
242 errno = err;
243 return (-1);
246 char *
247 fmd_fmri_strescape(const char *s)
249 return (strdup(s));
252 char *
253 fmd_fmri_strdup(const char *s)
255 return (strdup(s));
258 void
259 fmd_fmri_strfree(char *s)
261 free(s);
264 const char *
265 fmd_fmri_get_rootdir(void)
267 return (g_root ? g_root : "");
270 const char *
271 fmd_fmri_get_platform(void)
273 static char platform[MAXNAMELEN];
275 if (platform[0] == '\0')
276 (void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
278 return (platform);
281 uint64_t
282 fmd_fmri_get_drgen(void)
284 return (0);
288 fmd_fmri_set_errno(int err)
290 errno = err;
291 return (-1);
294 void
295 fmd_fmri_warn(const char *format, ...)
297 va_list ap;
299 va_start(ap, format);
300 fmdump_vwarn(format, ap);
301 va_end(ap);
304 struct topo_hdl *
305 fmd_fmri_topo_hold(int version)
307 int err;
309 if (version != TOPO_VERSION)
310 return (NULL);
312 if (g_thp == NULL) {
313 if ((g_thp = topo_open(TOPO_VERSION, "/", &err)) == NULL) {
314 (void) fprintf(stderr, "topo_open failed: %s\n",
315 topo_strerror(err));
316 exit(1);
320 return (g_thp);
323 /*ARGSUSED*/
324 void
325 fmd_fmri_topo_rele(struct topo_hdl *thp)
327 /* nothing to do */