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