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 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 79f6e214c7SGavin Maltby sw_fini(topo_mod_t *mod) 80f6e214c7SGavin Maltby { 81f6e214c7SGavin Maltby topo_mod_unregister(mod); 82f6e214c7SGavin Maltby } 83f6e214c7SGavin Maltby 84f6e214c7SGavin Maltby static int 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 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 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 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 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; 132f6e214c7SGavin Maltby topo_mod_errno_t moderr; 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; 284*aab83bb8SJosef '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 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 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 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 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