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]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <libnvpair.h>
27 #include <fm/topo_mod.h>
29 #include <sys/fm/protocol.h>
30 #include <sys/types.h>
32 #include <topo_method.h>
33 #include <topo_subr.h>
36 static int sw_fmri_nvl2str(topo_mod_t
*, tnode_t
*, topo_version_t
,
37 nvlist_t
*, nvlist_t
**);
38 static int sw_fmri_create(topo_mod_t
*, tnode_t
*, topo_version_t
,
39 nvlist_t
*, nvlist_t
**);
41 static const topo_method_t sw_methods
[] = {
42 { TOPO_METH_NVL2STR
, TOPO_METH_NVL2STR_DESC
, TOPO_METH_NVL2STR_VERSION
,
43 TOPO_STABILITY_INTERNAL
, sw_fmri_nvl2str
},
44 { TOPO_METH_FMRI
, TOPO_METH_FMRI_DESC
, TOPO_METH_FMRI_VERSION
,
45 TOPO_STABILITY_INTERNAL
, sw_fmri_create
},
49 static int sw_enum(topo_mod_t
*, tnode_t
*, const char *, topo_instance_t
,
50 topo_instance_t
, void *, void *);
51 static void sw_release(topo_mod_t
*, tnode_t
*);
53 static const topo_modops_t sw_ops
=
54 { sw_enum
, sw_release
};
56 static const topo_modinfo_t sw_info
=
57 { "sw", FM_FMRI_SCHEME_SW
, SW_VERSION
, &sw_ops
};
60 sw_init(topo_mod_t
*mod
, topo_version_t version
)
62 if (getenv("TOPOSWDEBUG"))
63 topo_mod_setdebug(mod
);
64 topo_mod_dprintf(mod
, "initializing sw builtin\n");
66 if (version
!= SW_VERSION
)
67 return (topo_mod_seterrno(mod
, EMOD_VER_NEW
));
69 if (topo_mod_register(mod
, &sw_info
, TOPO_VERSION
) != 0) {
70 topo_mod_dprintf(mod
, "failed to register sw_info: "
71 "%s\n", topo_mod_errmsg(mod
));
79 sw_fini(topo_mod_t
*mod
)
81 topo_mod_unregister(mod
);
85 sw_get_optl_string(nvlist_t
*nvl
, char *name
, char **dest
)
87 if (nvlist_lookup_string(nvl
, name
, dest
) == 0) {
91 return (errno
== ENOENT
? 0 : 1);
96 sw_get_optl_int64(nvlist_t
*nvl
, char *name
, int64_t *dest
)
98 if (nvlist_lookup_int64(nvl
, name
, dest
) == 0) {
102 return (errno
== ENOENT
? 0 : 1);
107 sw_get_optl_nvlist(nvlist_t
*nvl
, char *name
, nvlist_t
**dest
)
109 if (nvlist_lookup_nvlist(nvl
, name
, dest
) == 0) {
113 return (errno
== ENOENT
? 0 : 1);
118 sw_add_optl_string(nvlist_t
*nvl
, char *name
, char *val
)
121 return (nvlist_add_string(nvl
, name
, val
) != 0);
128 sw_fmri_create(topo_mod_t
*mod
, tnode_t
*node
, topo_version_t version
,
129 nvlist_t
*in
, nvlist_t
**out
)
131 nvlist_t
*args
, *fmri
= NULL
, *obj
= NULL
, *site
= NULL
, *ctxt
= NULL
;
132 topo_mod_errno_t moderr
= 0;
135 char *obj_path
, *obj_root
;
138 char *site_token
, *site_module
, *site_file
, *site_func
;
141 char *ctxt_origin
, *ctxt_execname
, *ctxt_zone
;
142 int64_t ctxt_pid
, ctxt_ctid
;
144 uint_t ctxt_stackdepth
;
147 if (version
> TOPO_METH_FMRI_VERSION
)
148 return (topo_mod_seterrno(mod
, EMOD_VER_NEW
));
150 if (nvlist_lookup_nvlist(in
, TOPO_METH_FMRI_ARG_NVL
, &args
) != 0)
151 return (topo_mod_seterrno(mod
, EMOD_METHOD_INVAL
));
153 if (nvlist_lookup_string(args
, "obj_path", &obj_path
) != 0)
154 return (topo_mod_seterrno(mod
, EMOD_NVL_INVAL
));
155 err
|= sw_get_optl_string(args
, "obj_root", &obj_root
);
156 err
|= sw_get_optl_nvlist(args
, "obj-pkg", &obj_pkg
);
158 err
|= sw_get_optl_string(args
, "site_token", &site_token
);
159 err
|= sw_get_optl_string(args
, "site_module", &site_module
);
160 err
|= sw_get_optl_string(args
, "site_file", &site_file
);
161 err
|= sw_get_optl_string(args
, "site_func", &site_func
);
162 err
|= sw_get_optl_int64(args
, "site_line", &site_line
);
164 err
|= sw_get_optl_string(args
, "ctxt_origin", &ctxt_origin
);
165 err
|= sw_get_optl_string(args
, "ctxt_execname", &ctxt_execname
);
166 err
|= sw_get_optl_string(args
, "ctxt_zone", &ctxt_zone
);
167 err
|= sw_get_optl_int64(args
, "ctxt_pid", &ctxt_pid
);
168 err
|= sw_get_optl_int64(args
, "ctxt_ctid", &ctxt_ctid
);
170 if (nvlist_lookup_string_array(args
, "stack", &ctxt_stack
,
171 &ctxt_stackdepth
) != 0) {
179 (void) topo_mod_seterrno(mod
, EMOD_FMRI_NVL
);
181 if (topo_mod_nvalloc(mod
, &fmri
, NV_UNIQUE_NAME
) != 0 ||
182 topo_mod_nvalloc(mod
, &obj
, NV_UNIQUE_NAME
) != 0) {
188 * Add standard FMRI members 'version' and 'scheme'.
190 err
|= nvlist_add_uint8(fmri
, FM_VERSION
, FM_SW_SCHEME_VERSION
);
191 err
|= nvlist_add_string(fmri
, FM_FMRI_SCHEME
, FM_FMRI_SCHEME_SW
);
194 * Build up the 'object' nvlist.
196 err
|= nvlist_add_string(obj
, FM_FMRI_SW_OBJ_PATH
, obj_path
);
197 err
|= sw_add_optl_string(obj
, FM_FMRI_SW_OBJ_ROOT
, obj_root
);
199 err
|= nvlist_add_nvlist(obj
, FM_FMRI_SW_OBJ_PKG
, obj_pkg
);
202 * Add 'object' to the fmri.
205 err
|= nvlist_add_nvlist(fmri
, FM_FMRI_SW_OBJ
, obj
);
213 * Do we have anything for a 'site' nvlist?
215 if (site_token
== NULL
&& site_module
== NULL
&& site_file
== NULL
&&
216 site_func
== NULL
&& site_line
== -1)
220 * Allocate and build 'site' nvlist.
222 if (topo_mod_nvalloc(mod
, &site
, NV_UNIQUE_NAME
) != 0) {
227 err
|= sw_add_optl_string(site
, FM_FMRI_SW_SITE_TOKEN
, site_token
);
228 err
|= sw_add_optl_string(site
, FM_FMRI_SW_SITE_MODULE
, site_module
);
229 err
|= sw_add_optl_string(site
, FM_FMRI_SW_SITE_FILE
, site_file
);
230 err
|= sw_add_optl_string(site
, FM_FMRI_SW_SITE_FUNC
, site_func
);
231 if ((site_token
|| site_module
|| site_file
|| site_func
) &&
233 err
|= nvlist_add_int64(site
, FM_FMRI_SW_SITE_LINE
, site_line
);
236 * Add 'site' to the fmri.
239 err
|= nvlist_add_nvlist(fmri
, FM_FMRI_SW_SITE
, site
);
248 * Do we have anything for a 'context' nvlist?
250 if (ctxt_origin
|| ctxt_execname
|| ctxt_zone
||
251 ctxt_pid
!= -1 || ctxt_ctid
!= -1 || ctxt_stack
!= NULL
)
255 * Allocate and build 'context' nvlist.
257 if (topo_mod_nvalloc(mod
, &ctxt
, NV_UNIQUE_NAME
) != 0) {
262 err
|= sw_add_optl_string(ctxt
, FM_FMRI_SW_CTXT_ORIGIN
, ctxt_origin
);
263 err
|= sw_add_optl_string(ctxt
, FM_FMRI_SW_CTXT_EXECNAME
,
265 err
|= sw_add_optl_string(ctxt
, FM_FMRI_SW_CTXT_ZONE
, ctxt_zone
);
267 err
|= nvlist_add_int64(ctxt
, FM_FMRI_SW_CTXT_PID
, ctxt_pid
);
269 err
|= nvlist_add_int64(ctxt
, FM_FMRI_SW_CTXT_CTID
, ctxt_ctid
);
270 if (ctxt_stack
!= NULL
)
271 err
|= nvlist_add_string_array(ctxt
, FM_FMRI_SW_CTXT_STACK
,
272 ctxt_stack
, ctxt_stackdepth
);
275 * Add 'context' to the fmri.
278 err
|= nvlist_add_nvlist(fmri
, FM_FMRI_SW_CTXT
, ctxt
);
280 moderr
= err
? EMOD_NOMEM
: 0;
291 return (moderr
== 0 ? 0 : topo_mod_seterrno(mod
, moderr
));
297 sw_enum(topo_mod_t
*mod
, tnode_t
*pnode
, const char *name
,
298 topo_instance_t min
, topo_instance_t max
, void *notused1
, void *notused2
)
300 (void) topo_method_register(mod
, pnode
, sw_methods
);
305 sw_release(topo_mod_t
*mod
, tnode_t
*node
)
307 topo_method_unregister_all(mod
, node
);
311 * Lookup a string in an nvlist. Possible return values:
312 * if 'required' is B_TRUE:
315 * if 'required' is B_FALSE:
317 * 0 = not found, but some error other than ENOENT encountered
318 * -1 = not found, with ENOENT
320 * So 0 is an error condition in both cases.
322 * In all "not found" cases, *valp is NULLed.
325 lookup_string(nvlist_t
*nvl
, char *name
, char **valp
, boolean_t required
)
329 err
= nvlist_lookup_string(nvl
, name
, valp
);
332 * A return value of 1 always means "found"
338 * Failure to lookup for whatever reason NULLs valp
343 * Return 0 if not found but required, or optional but some error
344 * other than ENOENT was returned.
346 if (required
== B_TRUE
|| err
!= ENOENT
)
350 * Return -1 if not found but was optional (and got ENOENT).
357 sw_fmri_nvl2str(topo_mod_t
*mod
, tnode_t
*node
, topo_version_t version
,
358 nvlist_t
*nvl
, nvlist_t
**out
)
360 nvlist_t
*object
, *site
= NULL
, *anvl
= NULL
;
361 char *file
, *func
, *token
;
362 uint8_t scheme_version
;
374 if (version
> TOPO_METH_NVL2STR_VERSION
)
375 return (topo_mod_seterrno(mod
, EMOD_VER_NEW
));
377 if (nvlist_lookup_uint8(nvl
, FM_VERSION
, &scheme_version
) != 0 ||
378 scheme_version
> FM_SW_SCHEME_VERSION
)
379 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
381 /* Get authority, if present */
382 err
= nvlist_lookup_nvlist(nvl
, FM_FMRI_AUTHORITY
, &anvl
);
383 if (err
!= 0 && err
!= ENOENT
)
384 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
387 * The 'object' nvlist is required. It must include the path,
388 * but the root is optional.
390 if (nvlist_lookup_nvlist(nvl
, FM_FMRI_SW_OBJ
, &object
) != 0 ||
391 !lookup_string(object
, FM_FMRI_SW_OBJ_PATH
, &path
, B_TRUE
) ||
392 !lookup_string(object
, FM_FMRI_SW_OBJ_ROOT
, &root
, B_FALSE
))
393 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
395 /* The 'site' nvlist is optional */
396 file
= func
= token
= NULL
;
398 if ((err
= nvlist_lookup_nvlist(nvl
, FM_FMRI_SW_SITE
, &site
)) == 0) {
400 * Prefer 'token' to file/func/line
402 if (lookup_string(site
, FM_FMRI_SW_SITE_TOKEN
, &token
,
405 * If no token then try file, func, line - but
406 * func and line are meaningless without file.
408 if (lookup_string(site
, FM_FMRI_SW_SITE_FILE
,
409 &file
, B_FALSE
) == 1) {
410 (void) lookup_string(site
, FM_FMRI_SW_SITE_FUNC
,
412 if (nvlist_lookup_int64(site
,
413 FM_FMRI_SW_SITE_LINE
, &line
) == 0)
417 } else if (err
!= ENOENT
) {
418 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
421 /* On the first pass buf is NULL and size and buflen are 0 */
425 * sw://[<authority>]/
426 * [:root=<object.root]
427 * :path=<object.path>
428 * [#<fragment-identifier>]
430 * <fragment-identifier> is one of
432 * :token=<site.token>
434 * :file=<site.file>[:func=<site.func>][:line=<site.line>]
438 topo_fmristr_build(&size
, buf
, buflen
, FM_FMRI_SCHEME_SW
,
441 /* authority, if any */
446 for (apair
= nvlist_next_nvpair(anvl
, NULL
);
447 apair
!= NULL
; apair
= nvlist_next_nvpair(anvl
, apair
)) {
448 if (nvpair_type(apair
) != DATA_TYPE_STRING
||
449 nvpair_value_string(apair
, &aval
) != 0)
451 aname
= nvpair_name(apair
);
452 topo_fmristr_build(&size
, buf
, buflen
, ":", NULL
, NULL
);
453 topo_fmristr_build(&size
, buf
, buflen
, "=",
458 /* separating slash */
459 topo_fmristr_build(&size
, buf
, buflen
, "/", NULL
, NULL
);
463 topo_fmristr_build(&size
, buf
, buflen
, root
,
464 ":" FM_FMRI_SW_OBJ_ROOT
"=", NULL
);
468 topo_fmristr_build(&size
, buf
, buflen
, path
,
469 ":" FM_FMRI_SW_OBJ_PATH
"=", NULL
);
473 topo_fmristr_build(&size
, buf
, buflen
, token
,
474 "#:" FM_FMRI_SW_SITE_TOKEN
"=", NULL
);
477 topo_fmristr_build(&size
, buf
, buflen
, file
,
478 "#:" FM_FMRI_SW_SITE_FILE
"=", NULL
);
482 topo_fmristr_build(&size
, buf
, buflen
, func
,
483 ":" FM_FMRI_SW_SITE_FUNC
"=", NULL
);
489 (void) snprintf(linebuf
, sizeof (linebuf
),
492 topo_fmristr_build(&size
, buf
, buflen
, linebuf
,
493 ":" FM_FMRI_SW_SITE_LINE
"=", NULL
);
498 if ((buf
= topo_mod_alloc(mod
, size
+ 1)) == NULL
)
499 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
508 * Construct the nvlist to return as the result.
510 if (topo_mod_nvalloc(mod
, &fmristr
, NV_UNIQUE_NAME
) != 0) {
511 topo_mod_strfree(mod
, buf
);
512 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
515 if (nvlist_add_string(fmristr
, "fmri-string", buf
) != 0) {
516 topo_mod_strfree(mod
, buf
);
517 nvlist_free(fmristr
);
518 return (topo_mod_seterrno(mod
, EMOD_NOMEM
));
520 topo_mod_strfree(mod
, buf
);