xref: /titanic_41/usr/src/lib/fm/topo/libtopo/common/sw.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
1*f6e214c7SGavin Maltby /*
2*f6e214c7SGavin Maltby  * CDDL HEADER START
3*f6e214c7SGavin Maltby  *
4*f6e214c7SGavin Maltby  * The contents of this file are subject to the terms of the
5*f6e214c7SGavin Maltby  * Common Development and Distribution License (the "License").
6*f6e214c7SGavin Maltby  * You may not use this file except in compliance with the License.
7*f6e214c7SGavin Maltby  *
8*f6e214c7SGavin Maltby  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f6e214c7SGavin Maltby  * or http://www.opensolaris.org/os/licensing.
10*f6e214c7SGavin Maltby  * See the License for the specific language governing permissions
11*f6e214c7SGavin Maltby  * and limitations under the License.
12*f6e214c7SGavin Maltby  *
13*f6e214c7SGavin Maltby  * When distributing Covered Code, include this CDDL HEADER in each
14*f6e214c7SGavin Maltby  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f6e214c7SGavin Maltby  * If applicable, add the following below this CDDL HEADER, with the
16*f6e214c7SGavin Maltby  * fields enclosed by brackets "[]" replaced with your own identifying
17*f6e214c7SGavin Maltby  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f6e214c7SGavin Maltby  *
19*f6e214c7SGavin Maltby  * CDDL HEADER END
20*f6e214c7SGavin Maltby  */
21*f6e214c7SGavin Maltby 
22*f6e214c7SGavin Maltby /*
23*f6e214c7SGavin Maltby  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*f6e214c7SGavin Maltby  */
25*f6e214c7SGavin Maltby 
26*f6e214c7SGavin Maltby #include <libnvpair.h>
27*f6e214c7SGavin Maltby #include <fm/topo_mod.h>
28*f6e214c7SGavin Maltby 
29*f6e214c7SGavin Maltby #include <sys/fm/protocol.h>
30*f6e214c7SGavin Maltby #include <sys/types.h>
31*f6e214c7SGavin Maltby 
32*f6e214c7SGavin Maltby #include <topo_method.h>
33*f6e214c7SGavin Maltby #include <topo_subr.h>
34*f6e214c7SGavin Maltby #include <sw.h>
35*f6e214c7SGavin Maltby 
36*f6e214c7SGavin Maltby static int sw_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t,
37*f6e214c7SGavin Maltby     nvlist_t *, nvlist_t **);
38*f6e214c7SGavin Maltby static int sw_fmri_create(topo_mod_t *, tnode_t *, topo_version_t,
39*f6e214c7SGavin Maltby     nvlist_t *, nvlist_t **);
40*f6e214c7SGavin Maltby 
41*f6e214c7SGavin Maltby static const topo_method_t sw_methods[] = {
42*f6e214c7SGavin Maltby 	{ TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION,
43*f6e214c7SGavin Maltby 	    TOPO_STABILITY_INTERNAL, sw_fmri_nvl2str },
44*f6e214c7SGavin Maltby 	{ TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION,
45*f6e214c7SGavin Maltby 	    TOPO_STABILITY_INTERNAL, sw_fmri_create },
46*f6e214c7SGavin Maltby 	{ NULL }
47*f6e214c7SGavin Maltby };
48*f6e214c7SGavin Maltby 
49*f6e214c7SGavin Maltby static int sw_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
50*f6e214c7SGavin Maltby     topo_instance_t, void *, void *);
51*f6e214c7SGavin Maltby static void sw_release(topo_mod_t *, tnode_t *);
52*f6e214c7SGavin Maltby 
53*f6e214c7SGavin Maltby static const topo_modops_t sw_ops =
54*f6e214c7SGavin Maltby 	{ sw_enum, sw_release };
55*f6e214c7SGavin Maltby 
56*f6e214c7SGavin Maltby static const topo_modinfo_t sw_info =
57*f6e214c7SGavin Maltby 	{ "sw", FM_FMRI_SCHEME_SW, SW_VERSION, &sw_ops };
58*f6e214c7SGavin Maltby 
59*f6e214c7SGavin Maltby int
sw_init(topo_mod_t * mod,topo_version_t version)60*f6e214c7SGavin Maltby sw_init(topo_mod_t *mod, topo_version_t version)
61*f6e214c7SGavin Maltby {
62*f6e214c7SGavin Maltby 	if (getenv("TOPOSWDEBUG"))
63*f6e214c7SGavin Maltby 		topo_mod_setdebug(mod);
64*f6e214c7SGavin Maltby 	topo_mod_dprintf(mod, "initializing sw builtin\n");
65*f6e214c7SGavin Maltby 
66*f6e214c7SGavin Maltby 	if (version != SW_VERSION)
67*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
68*f6e214c7SGavin Maltby 
69*f6e214c7SGavin Maltby 	if (topo_mod_register(mod, &sw_info, TOPO_VERSION) != 0) {
70*f6e214c7SGavin Maltby 		topo_mod_dprintf(mod, "failed to register sw_info: "
71*f6e214c7SGavin Maltby 		    "%s\n", topo_mod_errmsg(mod));
72*f6e214c7SGavin Maltby 		return (-1);
73*f6e214c7SGavin Maltby 	}
74*f6e214c7SGavin Maltby 
75*f6e214c7SGavin Maltby 	return (0);
76*f6e214c7SGavin Maltby }
77*f6e214c7SGavin Maltby 
78*f6e214c7SGavin Maltby void
sw_fini(topo_mod_t * mod)79*f6e214c7SGavin Maltby sw_fini(topo_mod_t *mod)
80*f6e214c7SGavin Maltby {
81*f6e214c7SGavin Maltby 	topo_mod_unregister(mod);
82*f6e214c7SGavin Maltby }
83*f6e214c7SGavin Maltby 
84*f6e214c7SGavin Maltby static int
sw_get_optl_string(nvlist_t * nvl,char * name,char ** dest)85*f6e214c7SGavin Maltby sw_get_optl_string(nvlist_t *nvl, char *name, char **dest)
86*f6e214c7SGavin Maltby {
87*f6e214c7SGavin Maltby 	if (nvlist_lookup_string(nvl, name, dest) == 0) {
88*f6e214c7SGavin Maltby 		return (0);
89*f6e214c7SGavin Maltby 	} else {
90*f6e214c7SGavin Maltby 		*dest = NULL;
91*f6e214c7SGavin Maltby 		return (errno == ENOENT ? 0 : 1);
92*f6e214c7SGavin Maltby 	}
93*f6e214c7SGavin Maltby }
94*f6e214c7SGavin Maltby 
95*f6e214c7SGavin Maltby static int
sw_get_optl_int64(nvlist_t * nvl,char * name,int64_t * dest)96*f6e214c7SGavin Maltby sw_get_optl_int64(nvlist_t *nvl, char *name, int64_t *dest)
97*f6e214c7SGavin Maltby {
98*f6e214c7SGavin Maltby 	if (nvlist_lookup_int64(nvl, name, dest) == 0) {
99*f6e214c7SGavin Maltby 		return (0);
100*f6e214c7SGavin Maltby 	} else {
101*f6e214c7SGavin Maltby 		*dest = -1;
102*f6e214c7SGavin Maltby 		return (errno == ENOENT ? 0 : 1);
103*f6e214c7SGavin Maltby 	}
104*f6e214c7SGavin Maltby }
105*f6e214c7SGavin Maltby 
106*f6e214c7SGavin Maltby static int
sw_get_optl_nvlist(nvlist_t * nvl,char * name,nvlist_t ** dest)107*f6e214c7SGavin Maltby sw_get_optl_nvlist(nvlist_t *nvl, char *name, nvlist_t **dest)
108*f6e214c7SGavin Maltby {
109*f6e214c7SGavin Maltby 	if (nvlist_lookup_nvlist(nvl, name, dest) == 0) {
110*f6e214c7SGavin Maltby 		return (0);
111*f6e214c7SGavin Maltby 	} else {
112*f6e214c7SGavin Maltby 		*dest = NULL;
113*f6e214c7SGavin Maltby 		return (errno == ENOENT ? 0 : 1);
114*f6e214c7SGavin Maltby 	}
115*f6e214c7SGavin Maltby }
116*f6e214c7SGavin Maltby 
117*f6e214c7SGavin Maltby static int
sw_add_optl_string(nvlist_t * nvl,char * name,char * val)118*f6e214c7SGavin Maltby sw_add_optl_string(nvlist_t *nvl, char *name, char *val)
119*f6e214c7SGavin Maltby {
120*f6e214c7SGavin Maltby 	if (val)
121*f6e214c7SGavin Maltby 		return (nvlist_add_string(nvl, name, val) != 0);
122*f6e214c7SGavin Maltby 	else
123*f6e214c7SGavin Maltby 		return (0);
124*f6e214c7SGavin Maltby }
125*f6e214c7SGavin Maltby 
126*f6e214c7SGavin Maltby /*ARGSUSED*/
127*f6e214c7SGavin Maltby static int
sw_fmri_create(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)128*f6e214c7SGavin Maltby sw_fmri_create(topo_mod_t *mod, tnode_t *node, topo_version_t version,
129*f6e214c7SGavin Maltby     nvlist_t *in, nvlist_t **out)
130*f6e214c7SGavin Maltby {
131*f6e214c7SGavin Maltby 	nvlist_t *args, *fmri = NULL, *obj = NULL, *site = NULL, *ctxt = NULL;
132*f6e214c7SGavin Maltby 	topo_mod_errno_t moderr;
133*f6e214c7SGavin Maltby 	int err = 0;
134*f6e214c7SGavin Maltby 
135*f6e214c7SGavin Maltby 	char *obj_path, *obj_root;
136*f6e214c7SGavin Maltby 	nvlist_t *obj_pkg;
137*f6e214c7SGavin Maltby 
138*f6e214c7SGavin Maltby 	char *site_token, *site_module, *site_file, *site_func;
139*f6e214c7SGavin Maltby 	int64_t site_line;
140*f6e214c7SGavin Maltby 
141*f6e214c7SGavin Maltby 	char *ctxt_origin, *ctxt_execname, *ctxt_zone;
142*f6e214c7SGavin Maltby 	int64_t ctxt_pid, ctxt_ctid;
143*f6e214c7SGavin Maltby 	char **ctxt_stack;
144*f6e214c7SGavin Maltby 	uint_t ctxt_stackdepth;
145*f6e214c7SGavin Maltby 
146*f6e214c7SGavin Maltby 
147*f6e214c7SGavin Maltby 	if (version > TOPO_METH_FMRI_VERSION)
148*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
149*f6e214c7SGavin Maltby 
150*f6e214c7SGavin Maltby 	if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args) != 0)
151*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
152*f6e214c7SGavin Maltby 
153*f6e214c7SGavin Maltby 	if (nvlist_lookup_string(args, "obj_path", &obj_path) != 0)
154*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
155*f6e214c7SGavin Maltby 	err |= sw_get_optl_string(args, "obj_root", &obj_root);
156*f6e214c7SGavin Maltby 	err |= sw_get_optl_nvlist(args, "obj-pkg", &obj_pkg);
157*f6e214c7SGavin Maltby 
158*f6e214c7SGavin Maltby 	err |= sw_get_optl_string(args, "site_token", &site_token);
159*f6e214c7SGavin Maltby 	err |= sw_get_optl_string(args, "site_module", &site_module);
160*f6e214c7SGavin Maltby 	err |= sw_get_optl_string(args, "site_file", &site_file);
161*f6e214c7SGavin Maltby 	err |= sw_get_optl_string(args, "site_func", &site_func);
162*f6e214c7SGavin Maltby 	err |= sw_get_optl_int64(args, "site_line", &site_line);
163*f6e214c7SGavin Maltby 
164*f6e214c7SGavin Maltby 	err |= sw_get_optl_string(args, "ctxt_origin", &ctxt_origin);
165*f6e214c7SGavin Maltby 	err |= sw_get_optl_string(args, "ctxt_execname", &ctxt_execname);
166*f6e214c7SGavin Maltby 	err |= sw_get_optl_string(args, "ctxt_zone", &ctxt_zone);
167*f6e214c7SGavin Maltby 	err |= sw_get_optl_int64(args, "ctxt_pid", &ctxt_pid);
168*f6e214c7SGavin Maltby 	err |= sw_get_optl_int64(args, "ctxt_ctid", &ctxt_ctid);
169*f6e214c7SGavin Maltby 
170*f6e214c7SGavin Maltby 	if (nvlist_lookup_string_array(args, "stack", &ctxt_stack,
171*f6e214c7SGavin Maltby 	    &ctxt_stackdepth) != 0) {
172*f6e214c7SGavin Maltby 		if (errno == ENOENT)
173*f6e214c7SGavin Maltby 			ctxt_stack = NULL;
174*f6e214c7SGavin Maltby 		else
175*f6e214c7SGavin Maltby 			err++;
176*f6e214c7SGavin Maltby 	}
177*f6e214c7SGavin Maltby 
178*f6e214c7SGavin Maltby 	if (err)
179*f6e214c7SGavin Maltby 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
180*f6e214c7SGavin Maltby 
181*f6e214c7SGavin Maltby 	if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0 ||
182*f6e214c7SGavin Maltby 	    topo_mod_nvalloc(mod, &obj, NV_UNIQUE_NAME) != 0) {
183*f6e214c7SGavin Maltby 		moderr = EMOD_NOMEM;
184*f6e214c7SGavin Maltby 		goto out;
185*f6e214c7SGavin Maltby 	}
186*f6e214c7SGavin Maltby 
187*f6e214c7SGavin Maltby 	/*
188*f6e214c7SGavin Maltby 	 * Add standard FMRI members 'version' and 'scheme'.
189*f6e214c7SGavin Maltby 	 */
190*f6e214c7SGavin Maltby 	err |= nvlist_add_uint8(fmri, FM_VERSION, FM_SW_SCHEME_VERSION);
191*f6e214c7SGavin Maltby 	err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SW);
192*f6e214c7SGavin Maltby 
193*f6e214c7SGavin Maltby 	/*
194*f6e214c7SGavin Maltby 	 * Build up the 'object' nvlist.
195*f6e214c7SGavin Maltby 	 */
196*f6e214c7SGavin Maltby 	err |= nvlist_add_string(obj, FM_FMRI_SW_OBJ_PATH, obj_path);
197*f6e214c7SGavin Maltby 	err |= sw_add_optl_string(obj, FM_FMRI_SW_OBJ_ROOT, obj_root);
198*f6e214c7SGavin Maltby 	if (obj_pkg)
199*f6e214c7SGavin Maltby 		err |= nvlist_add_nvlist(obj, FM_FMRI_SW_OBJ_PKG, obj_pkg);
200*f6e214c7SGavin Maltby 
201*f6e214c7SGavin Maltby 	/*
202*f6e214c7SGavin Maltby 	 * Add 'object' to the fmri.
203*f6e214c7SGavin Maltby 	 */
204*f6e214c7SGavin Maltby 	if (err == 0)
205*f6e214c7SGavin Maltby 		err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_OBJ, obj);
206*f6e214c7SGavin Maltby 
207*f6e214c7SGavin Maltby 	if (err) {
208*f6e214c7SGavin Maltby 		moderr = EMOD_NOMEM;
209*f6e214c7SGavin Maltby 		goto out;
210*f6e214c7SGavin Maltby 	}
211*f6e214c7SGavin Maltby 
212*f6e214c7SGavin Maltby 	/*
213*f6e214c7SGavin Maltby 	 * Do we have anything for a 'site' nvlist?
214*f6e214c7SGavin Maltby 	 */
215*f6e214c7SGavin Maltby 	if (site_token == NULL && site_module == NULL && site_file == NULL &&
216*f6e214c7SGavin Maltby 	    site_func == NULL && site_line == -1)
217*f6e214c7SGavin Maltby 		goto context;
218*f6e214c7SGavin Maltby 
219*f6e214c7SGavin Maltby 	/*
220*f6e214c7SGavin Maltby 	 * Allocate and build 'site' nvlist.
221*f6e214c7SGavin Maltby 	 */
222*f6e214c7SGavin Maltby 	if (topo_mod_nvalloc(mod, &site, NV_UNIQUE_NAME) != 0) {
223*f6e214c7SGavin Maltby 		moderr = EMOD_NOMEM;
224*f6e214c7SGavin Maltby 		goto out;
225*f6e214c7SGavin Maltby 	}
226*f6e214c7SGavin Maltby 
227*f6e214c7SGavin Maltby 	err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_TOKEN, site_token);
228*f6e214c7SGavin Maltby 	err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_MODULE, site_module);
229*f6e214c7SGavin Maltby 	err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_FILE, site_file);
230*f6e214c7SGavin Maltby 	err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_FUNC, site_func);
231*f6e214c7SGavin Maltby 	if ((site_token || site_module || site_file || site_func) &&
232*f6e214c7SGavin Maltby 	    site_line != -1)
233*f6e214c7SGavin Maltby 		err |= nvlist_add_int64(site, FM_FMRI_SW_SITE_LINE, site_line);
234*f6e214c7SGavin Maltby 
235*f6e214c7SGavin Maltby 	/*
236*f6e214c7SGavin Maltby 	 * Add 'site' to the fmri.
237*f6e214c7SGavin Maltby 	 */
238*f6e214c7SGavin Maltby 	if (err == 0)
239*f6e214c7SGavin Maltby 		err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_SITE, site);
240*f6e214c7SGavin Maltby 
241*f6e214c7SGavin Maltby 	if (err) {
242*f6e214c7SGavin Maltby 		moderr = EMOD_NOMEM;
243*f6e214c7SGavin Maltby 		goto out;
244*f6e214c7SGavin Maltby 	}
245*f6e214c7SGavin Maltby 
246*f6e214c7SGavin Maltby context:
247*f6e214c7SGavin Maltby 	/*
248*f6e214c7SGavin Maltby 	 * Do we have anything for a 'context' nvlist?
249*f6e214c7SGavin Maltby 	 */
250*f6e214c7SGavin Maltby 	if (ctxt_origin || ctxt_execname || ctxt_zone ||
251*f6e214c7SGavin Maltby 	    ctxt_pid != -1 || ctxt_ctid != -1 || ctxt_stack != NULL)
252*f6e214c7SGavin Maltby 		goto out;
253*f6e214c7SGavin Maltby 
254*f6e214c7SGavin Maltby 	/*
255*f6e214c7SGavin Maltby 	 * Allocate and build 'context' nvlist.
256*f6e214c7SGavin Maltby 	 */
257*f6e214c7SGavin Maltby 	if (topo_mod_nvalloc(mod, &ctxt, NV_UNIQUE_NAME) != 0) {
258*f6e214c7SGavin Maltby 		moderr = EMOD_NOMEM;
259*f6e214c7SGavin Maltby 		goto out;
260*f6e214c7SGavin Maltby 	}
261*f6e214c7SGavin Maltby 
262*f6e214c7SGavin Maltby 	err |= sw_add_optl_string(ctxt, FM_FMRI_SW_CTXT_ORIGIN, ctxt_origin);
263*f6e214c7SGavin Maltby 	err |= sw_add_optl_string(ctxt, FM_FMRI_SW_CTXT_EXECNAME,
264*f6e214c7SGavin Maltby 	    ctxt_execname);
265*f6e214c7SGavin Maltby 	err |= sw_add_optl_string(ctxt, FM_FMRI_SW_CTXT_ZONE, ctxt_zone);
266*f6e214c7SGavin Maltby 	if (ctxt_pid != -1)
267*f6e214c7SGavin Maltby 		err |= nvlist_add_int64(ctxt, FM_FMRI_SW_CTXT_PID, ctxt_pid);
268*f6e214c7SGavin Maltby 	if (ctxt_ctid != -1)
269*f6e214c7SGavin Maltby 		err |= nvlist_add_int64(ctxt, FM_FMRI_SW_CTXT_CTID, ctxt_ctid);
270*f6e214c7SGavin Maltby 	if (ctxt_stack != NULL)
271*f6e214c7SGavin Maltby 		err |= nvlist_add_string_array(ctxt, FM_FMRI_SW_CTXT_STACK,
272*f6e214c7SGavin Maltby 		    ctxt_stack, ctxt_stackdepth);
273*f6e214c7SGavin Maltby 
274*f6e214c7SGavin Maltby 	/*
275*f6e214c7SGavin Maltby 	 * Add 'context' to the fmri.
276*f6e214c7SGavin Maltby 	 */
277*f6e214c7SGavin Maltby 	if (err == 0)
278*f6e214c7SGavin Maltby 		err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_CTXT, ctxt);
279*f6e214c7SGavin Maltby 
280*f6e214c7SGavin Maltby 	moderr = err ? EMOD_NOMEM : 0;
281*f6e214c7SGavin Maltby out:
282*f6e214c7SGavin Maltby 	if (moderr == 0)
283*f6e214c7SGavin Maltby 		*out = fmri;
284*f6e214c7SGavin Maltby 
285*f6e214c7SGavin Maltby 	if (moderr != 0 && fmri)
286*f6e214c7SGavin Maltby 		nvlist_free(fmri);
287*f6e214c7SGavin Maltby 
288*f6e214c7SGavin Maltby 	if (obj)
289*f6e214c7SGavin Maltby 		nvlist_free(obj);
290*f6e214c7SGavin Maltby 
291*f6e214c7SGavin Maltby 	if (site)
292*f6e214c7SGavin Maltby 		nvlist_free(site);
293*f6e214c7SGavin Maltby 
294*f6e214c7SGavin Maltby 	if (ctxt)
295*f6e214c7SGavin Maltby 		nvlist_free(ctxt);
296*f6e214c7SGavin Maltby 
297*f6e214c7SGavin Maltby 	return (moderr == 0 ? 0 : topo_mod_seterrno(mod, moderr));
298*f6e214c7SGavin Maltby }
299*f6e214c7SGavin Maltby 
300*f6e214c7SGavin Maltby 
301*f6e214c7SGavin Maltby /*ARGSUSED*/
302*f6e214c7SGavin Maltby static int
sw_enum(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max,void * notused1,void * notused2)303*f6e214c7SGavin Maltby sw_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
304*f6e214c7SGavin Maltby     topo_instance_t min, topo_instance_t max, void *notused1, void *notused2)
305*f6e214c7SGavin Maltby {
306*f6e214c7SGavin Maltby 	(void) topo_method_register(mod, pnode, sw_methods);
307*f6e214c7SGavin Maltby 	return (0);
308*f6e214c7SGavin Maltby }
309*f6e214c7SGavin Maltby 
310*f6e214c7SGavin Maltby static void
sw_release(topo_mod_t * mod,tnode_t * node)311*f6e214c7SGavin Maltby sw_release(topo_mod_t *mod, tnode_t *node)
312*f6e214c7SGavin Maltby {
313*f6e214c7SGavin Maltby 	topo_method_unregister_all(mod, node);
314*f6e214c7SGavin Maltby }
315*f6e214c7SGavin Maltby 
316*f6e214c7SGavin Maltby /*
317*f6e214c7SGavin Maltby  * Lookup a string in an nvlist.  Possible return values:
318*f6e214c7SGavin Maltby  *	if 'required' is B_TRUE:
319*f6e214c7SGavin Maltby  *		1 = found
320*f6e214c7SGavin Maltby  *		0 = not found
321*f6e214c7SGavin Maltby  *	if 'required' is B_FALSE:
322*f6e214c7SGavin Maltby  *		1 = found
323*f6e214c7SGavin Maltby  *		0 = not found, but some error other than ENOENT encountered
324*f6e214c7SGavin Maltby  *		-1 = not found, with ENOENT
325*f6e214c7SGavin Maltby  *
326*f6e214c7SGavin Maltby  *	So 0 is an error condition in both cases.
327*f6e214c7SGavin Maltby  *
328*f6e214c7SGavin Maltby  *	In all "not found" cases, *valp is NULLed.
329*f6e214c7SGavin Maltby  */
330*f6e214c7SGavin Maltby static int
lookup_string(nvlist_t * nvl,char * name,char ** valp,boolean_t required)331*f6e214c7SGavin Maltby lookup_string(nvlist_t *nvl, char *name, char **valp, boolean_t required)
332*f6e214c7SGavin Maltby {
333*f6e214c7SGavin Maltby 	int err;
334*f6e214c7SGavin Maltby 
335*f6e214c7SGavin Maltby 	err = nvlist_lookup_string(nvl, name, valp);
336*f6e214c7SGavin Maltby 
337*f6e214c7SGavin Maltby 	/*
338*f6e214c7SGavin Maltby 	 * A return value of 1 always means "found"
339*f6e214c7SGavin Maltby 	 */
340*f6e214c7SGavin Maltby 	if (err == 0)
341*f6e214c7SGavin Maltby 		return (1);
342*f6e214c7SGavin Maltby 
343*f6e214c7SGavin Maltby 	/*
344*f6e214c7SGavin Maltby 	 * Failure to lookup for whatever reason NULLs valp
345*f6e214c7SGavin Maltby 	 */
346*f6e214c7SGavin Maltby 	*valp = NULL;
347*f6e214c7SGavin Maltby 
348*f6e214c7SGavin Maltby 	/*
349*f6e214c7SGavin Maltby 	 * Return 0 if not found but required, or optional but some error
350*f6e214c7SGavin Maltby 	 * other than ENOENT was returned.
351*f6e214c7SGavin Maltby 	 */
352*f6e214c7SGavin Maltby 	if (required == B_TRUE || err != ENOENT)
353*f6e214c7SGavin Maltby 		return (0);
354*f6e214c7SGavin Maltby 
355*f6e214c7SGavin Maltby 	/*
356*f6e214c7SGavin Maltby 	 * Return -1 if not found but was optional (and got ENOENT).
357*f6e214c7SGavin Maltby 	 */
358*f6e214c7SGavin Maltby 	return (-1);
359*f6e214c7SGavin Maltby }
360*f6e214c7SGavin Maltby 
361*f6e214c7SGavin Maltby /*ARGSUSED*/
362*f6e214c7SGavin Maltby static int
sw_fmri_nvl2str(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * nvl,nvlist_t ** out)363*f6e214c7SGavin Maltby sw_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version,
364*f6e214c7SGavin Maltby     nvlist_t *nvl, nvlist_t **out)
365*f6e214c7SGavin Maltby {
366*f6e214c7SGavin Maltby 	nvlist_t *object, *site = NULL, *anvl = NULL;
367*f6e214c7SGavin Maltby 	char *file, *func, *token;
368*f6e214c7SGavin Maltby 	uint8_t scheme_version;
369*f6e214c7SGavin Maltby 	char *path, *root;
370*f6e214c7SGavin Maltby 	nvlist_t *fmristr;
371*f6e214c7SGavin Maltby 	size_t buflen = 0;
372*f6e214c7SGavin Maltby 	int linevalid = 0;
373*f6e214c7SGavin Maltby 	char *buf = NULL;
374*f6e214c7SGavin Maltby 	ssize_t size = 0;
375*f6e214c7SGavin Maltby 	char linebuf[32];
376*f6e214c7SGavin Maltby 	int64_t line;
377*f6e214c7SGavin Maltby 	int pass;
378*f6e214c7SGavin Maltby 	int err;
379*f6e214c7SGavin Maltby 
380*f6e214c7SGavin Maltby 	if (version > TOPO_METH_NVL2STR_VERSION)
381*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
382*f6e214c7SGavin Maltby 
383*f6e214c7SGavin Maltby 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &scheme_version) != 0 ||
384*f6e214c7SGavin Maltby 	    scheme_version > FM_SW_SCHEME_VERSION)
385*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
386*f6e214c7SGavin Maltby 
387*f6e214c7SGavin Maltby 	/* Get authority, if present */
388*f6e214c7SGavin Maltby 	err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl);
389*f6e214c7SGavin Maltby 	if (err != 0 && err != ENOENT)
390*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
391*f6e214c7SGavin Maltby 
392*f6e214c7SGavin Maltby 	/*
393*f6e214c7SGavin Maltby 	 * The 'object' nvlist is required. It must include the path,
394*f6e214c7SGavin Maltby 	 * but the root is optional.
395*f6e214c7SGavin Maltby 	 */
396*f6e214c7SGavin Maltby 	if (nvlist_lookup_nvlist(nvl, FM_FMRI_SW_OBJ, &object) != 0 ||
397*f6e214c7SGavin Maltby 	    !lookup_string(object, FM_FMRI_SW_OBJ_PATH, &path, B_TRUE) ||
398*f6e214c7SGavin Maltby 	    !lookup_string(object, FM_FMRI_SW_OBJ_ROOT, &root, B_FALSE))
399*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
400*f6e214c7SGavin Maltby 
401*f6e214c7SGavin Maltby 	/* The 'site' nvlist is optional */
402*f6e214c7SGavin Maltby 	file = func = token = NULL;
403*f6e214c7SGavin Maltby 	linevalid = 0;
404*f6e214c7SGavin Maltby 	if ((err = nvlist_lookup_nvlist(nvl, FM_FMRI_SW_SITE, &site)) == 0) {
405*f6e214c7SGavin Maltby 		/*
406*f6e214c7SGavin Maltby 		 * Prefer 'token' to file/func/line
407*f6e214c7SGavin Maltby 		 */
408*f6e214c7SGavin Maltby 		if (lookup_string(site, FM_FMRI_SW_SITE_TOKEN, &token,
409*f6e214c7SGavin Maltby 		    B_FALSE) <= 0) {
410*f6e214c7SGavin Maltby 			/*
411*f6e214c7SGavin Maltby 			 * If no token then try file, func, line - but
412*f6e214c7SGavin Maltby 			 * func and line are meaningless without file.
413*f6e214c7SGavin Maltby 			 */
414*f6e214c7SGavin Maltby 			if (lookup_string(site, FM_FMRI_SW_SITE_FILE,
415*f6e214c7SGavin Maltby 			    &file, B_FALSE) == 1) {
416*f6e214c7SGavin Maltby 				(void) lookup_string(site, FM_FMRI_SW_SITE_FUNC,
417*f6e214c7SGavin Maltby 				    &func, B_FALSE);
418*f6e214c7SGavin Maltby 				if (nvlist_lookup_int64(site,
419*f6e214c7SGavin Maltby 				    FM_FMRI_SW_SITE_LINE, &line) == 0)
420*f6e214c7SGavin Maltby 					linevalid = 1;
421*f6e214c7SGavin Maltby 			}
422*f6e214c7SGavin Maltby 		}
423*f6e214c7SGavin Maltby 	} else if (err != ENOENT) {
424*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
425*f6e214c7SGavin Maltby 	}
426*f6e214c7SGavin Maltby 
427*f6e214c7SGavin Maltby 	/* On the first pass buf is NULL and size and buflen are 0 */
428*f6e214c7SGavin Maltby 	pass = 1;
429*f6e214c7SGavin Maltby again:
430*f6e214c7SGavin Maltby 	/*
431*f6e214c7SGavin Maltby 	 * sw://[<authority>]/
432*f6e214c7SGavin Maltby 	 *	[:root=<object.root]
433*f6e214c7SGavin Maltby 	 *	:path=<object.path>
434*f6e214c7SGavin Maltby 	 *	[#<fragment-identifier>]
435*f6e214c7SGavin Maltby 	 *
436*f6e214c7SGavin Maltby 	 *	<fragment-identifier> is one of
437*f6e214c7SGavin Maltby 	 *
438*f6e214c7SGavin Maltby 	 *		:token=<site.token>
439*f6e214c7SGavin Maltby 	 *	or
440*f6e214c7SGavin Maltby 	 *		:file=<site.file>[:func=<site.func>][:line=<site.line>]
441*f6e214c7SGavin Maltby 	 */
442*f6e214c7SGavin Maltby 
443*f6e214c7SGavin Maltby 	/* sw:// */
444*f6e214c7SGavin Maltby 	topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_SW,
445*f6e214c7SGavin Maltby 	    NULL, "://");
446*f6e214c7SGavin Maltby 
447*f6e214c7SGavin Maltby 	/* authority, if any */
448*f6e214c7SGavin Maltby 	if (anvl != NULL) {
449*f6e214c7SGavin Maltby 		nvpair_t *apair;
450*f6e214c7SGavin Maltby 		char *aname, *aval;
451*f6e214c7SGavin Maltby 
452*f6e214c7SGavin Maltby 		for (apair = nvlist_next_nvpair(anvl, NULL);
453*f6e214c7SGavin Maltby 		    apair != NULL; apair = nvlist_next_nvpair(anvl, apair)) {
454*f6e214c7SGavin Maltby 			if (nvpair_type(apair) != DATA_TYPE_STRING ||
455*f6e214c7SGavin Maltby 			    nvpair_value_string(apair, &aval) != 0)
456*f6e214c7SGavin Maltby 				continue;
457*f6e214c7SGavin Maltby 			aname = nvpair_name(apair);
458*f6e214c7SGavin Maltby 			topo_fmristr_build(&size, buf, buflen, ":", NULL, NULL);
459*f6e214c7SGavin Maltby 			topo_fmristr_build(&size, buf, buflen, "=",
460*f6e214c7SGavin Maltby 			    aname, aval);
461*f6e214c7SGavin Maltby 		}
462*f6e214c7SGavin Maltby 	}
463*f6e214c7SGavin Maltby 
464*f6e214c7SGavin Maltby 	/* separating slash */
465*f6e214c7SGavin Maltby 	topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
466*f6e214c7SGavin Maltby 
467*f6e214c7SGavin Maltby 	/* :root=... */
468*f6e214c7SGavin Maltby 	if (root) {
469*f6e214c7SGavin Maltby 		topo_fmristr_build(&size, buf, buflen, root,
470*f6e214c7SGavin Maltby 		    ":" FM_FMRI_SW_OBJ_ROOT "=", NULL);
471*f6e214c7SGavin Maltby 	}
472*f6e214c7SGavin Maltby 
473*f6e214c7SGavin Maltby 	/* :path=... */
474*f6e214c7SGavin Maltby 	topo_fmristr_build(&size, buf, buflen, path,
475*f6e214c7SGavin Maltby 	    ":" FM_FMRI_SW_OBJ_PATH "=", NULL);
476*f6e214c7SGavin Maltby 
477*f6e214c7SGavin Maltby 	if (token) {
478*f6e214c7SGavin Maltby 		/* #:token=... */
479*f6e214c7SGavin Maltby 		topo_fmristr_build(&size, buf, buflen, token,
480*f6e214c7SGavin Maltby 		    "#:" FM_FMRI_SW_SITE_TOKEN "=", NULL);
481*f6e214c7SGavin Maltby 	} else if (file) {
482*f6e214c7SGavin Maltby 		/* #:file=... */
483*f6e214c7SGavin Maltby 		topo_fmristr_build(&size, buf, buflen, file,
484*f6e214c7SGavin Maltby 		    "#:" FM_FMRI_SW_SITE_FILE "=", NULL);
485*f6e214c7SGavin Maltby 
486*f6e214c7SGavin Maltby 		/* :func=... */
487*f6e214c7SGavin Maltby 		if (func) {
488*f6e214c7SGavin Maltby 			topo_fmristr_build(&size, buf, buflen, func,
489*f6e214c7SGavin Maltby 			    ":" FM_FMRI_SW_SITE_FUNC "=", NULL);
490*f6e214c7SGavin Maltby 		}
491*f6e214c7SGavin Maltby 
492*f6e214c7SGavin Maltby 		/* :line=... */
493*f6e214c7SGavin Maltby 		if (linevalid) {
494*f6e214c7SGavin Maltby 			if (pass == 1)
495*f6e214c7SGavin Maltby 				(void) snprintf(linebuf, sizeof (linebuf),
496*f6e214c7SGavin Maltby 				    "%lld", line);
497*f6e214c7SGavin Maltby 
498*f6e214c7SGavin Maltby 			topo_fmristr_build(&size, buf, buflen, linebuf,
499*f6e214c7SGavin Maltby 			    ":" FM_FMRI_SW_SITE_LINE "=", NULL);
500*f6e214c7SGavin Maltby 		}
501*f6e214c7SGavin Maltby 	}
502*f6e214c7SGavin Maltby 
503*f6e214c7SGavin Maltby 	if (buf == NULL) {
504*f6e214c7SGavin Maltby 		if ((buf = topo_mod_alloc(mod, size + 1)) == NULL)
505*f6e214c7SGavin Maltby 			return (topo_mod_seterrno(mod, EMOD_NOMEM));
506*f6e214c7SGavin Maltby 
507*f6e214c7SGavin Maltby 		buflen = size + 1;
508*f6e214c7SGavin Maltby 		size = 0;
509*f6e214c7SGavin Maltby 		pass = 2;
510*f6e214c7SGavin Maltby 		goto again;
511*f6e214c7SGavin Maltby 	}
512*f6e214c7SGavin Maltby 
513*f6e214c7SGavin Maltby 	/*
514*f6e214c7SGavin Maltby 	 * Construct the nvlist to return as the result.
515*f6e214c7SGavin Maltby 	 */
516*f6e214c7SGavin Maltby 	if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) {
517*f6e214c7SGavin Maltby 		topo_mod_strfree(mod, buf);
518*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
519*f6e214c7SGavin Maltby 	}
520*f6e214c7SGavin Maltby 
521*f6e214c7SGavin Maltby 	if (nvlist_add_string(fmristr, "fmri-string", buf) != 0) {
522*f6e214c7SGavin Maltby 		topo_mod_strfree(mod, buf);
523*f6e214c7SGavin Maltby 		nvlist_free(fmristr);
524*f6e214c7SGavin Maltby 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
525*f6e214c7SGavin Maltby 	}
526*f6e214c7SGavin Maltby 	topo_mod_strfree(mod, buf);
527*f6e214c7SGavin Maltby 	*out = fmristr;
528*f6e214c7SGavin Maltby 
529*f6e214c7SGavin Maltby 	return (0);
530*f6e214c7SGavin Maltby }
531