1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <limits.h> 30 #include <strings.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <stdio.h> 34 #include <alloca.h> 35 #include <libnvpair.h> 36 #include <fm/topo_mod.h> 37 #include <sys/fm/protocol.h> 38 39 #include <topo_subr.h> 40 #include <topo_error.h> 41 42 static int dev_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 43 topo_instance_t, void *); 44 static void dev_release(topo_mod_t *, tnode_t *); 45 static int dev_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 46 nvlist_t *, nvlist_t **); 47 static int dev_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, 48 nvlist_t *, nvlist_t **); 49 static int dev_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, 50 nvlist_t *, nvlist_t **); 51 52 #define DEV_VERSION TOPO_VERSION 53 54 static const topo_method_t dev_methods[] = { 55 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 56 TOPO_STABILITY_INTERNAL, dev_fmri_nvl2str }, 57 { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 58 TOPO_STABILITY_INTERNAL, dev_fmri_str2nvl }, 59 { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, 60 TOPO_STABILITY_INTERNAL, dev_fmri_create_meth }, 61 { NULL } 62 }; 63 64 static const topo_modinfo_t dev_info = 65 { "dev", DEV_VERSION, dev_enum, dev_release }; 66 67 void 68 dev_init(topo_mod_t *mod) 69 { 70 topo_mod_setdebug(mod, TOPO_DBG_ALL); 71 topo_mod_dprintf(mod, "initializing dev builtin\n"); 72 73 if (topo_mod_register(mod, &dev_info, NULL) != 0) { 74 topo_mod_dprintf(mod, "failed to register dev_info: " 75 "%s\n", topo_mod_errmsg(mod)); 76 return; 77 } 78 } 79 80 void 81 dev_fini(topo_mod_t *mod) 82 { 83 topo_mod_unregister(mod); 84 } 85 86 /*ARGSUSED*/ 87 static int 88 dev_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 89 topo_instance_t min, topo_instance_t max, void *arg) 90 { 91 (void) topo_method_register(mod, pnode, dev_methods); 92 return (0); 93 } 94 95 static void 96 dev_release(topo_mod_t *mod, tnode_t *node) 97 { 98 topo_method_unregister_all(mod, node); 99 } 100 101 static ssize_t 102 fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 103 { 104 nvlist_t *anvl = NULL; 105 uint8_t version; 106 ssize_t size = 0; 107 char *devid = NULL; 108 char *devpath = NULL; 109 char *achas = NULL; 110 char *adom = NULL; 111 char *aprod = NULL; 112 char *asrvr = NULL; 113 char *ahost = NULL; 114 int more_auth = 0; 115 int err; 116 117 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 118 version > FM_DEV_SCHEME_VERSION) 119 return (-1); 120 121 /* Get authority, if present */ 122 err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); 123 if (err != 0 && err != ENOENT) 124 return (-1); 125 126 /* Get devid, if present */ 127 err = nvlist_lookup_string(nvl, FM_FMRI_DEV_ID, &devid); 128 if (err != 0 && err != ENOENT) 129 return (-1); 130 131 /* There must be a device path present */ 132 err = nvlist_lookup_string(nvl, FM_FMRI_DEV_PATH, &devpath); 133 if (err != 0 || devpath == NULL) 134 return (-1); 135 136 if (anvl != NULL) { 137 (void) nvlist_lookup_string(anvl, 138 FM_FMRI_AUTH_PRODUCT, &aprod); 139 (void) nvlist_lookup_string(anvl, 140 FM_FMRI_AUTH_CHASSIS, &achas); 141 (void) nvlist_lookup_string(anvl, 142 FM_FMRI_AUTH_DOMAIN, &adom); 143 (void) nvlist_lookup_string(anvl, 144 FM_FMRI_AUTH_SERVER, &asrvr); 145 (void) nvlist_lookup_string(anvl, 146 FM_FMRI_AUTH_HOST, &ahost); 147 if (aprod != NULL) 148 more_auth++; 149 if (achas != NULL) 150 more_auth++; 151 if (adom != NULL) 152 more_auth++; 153 if (asrvr != NULL) 154 more_auth++; 155 if (ahost != NULL) 156 more_auth++; 157 } 158 159 /* dev:// */ 160 topo_fmristr_build(&size, 161 buf, buflen, FM_FMRI_SCHEME_DEV, NULL, "://"); 162 163 /* authority, if any */ 164 if (aprod != NULL) 165 topo_fmristr_build(&size, 166 buf, buflen, aprod, FM_FMRI_AUTH_PRODUCT "=", 167 --more_auth > 0 ? "," : NULL); 168 if (achas != NULL) 169 topo_fmristr_build(&size, 170 buf, buflen, achas, FM_FMRI_AUTH_CHASSIS "=", 171 --more_auth > 0 ? "," : NULL); 172 if (adom != NULL) 173 topo_fmristr_build(&size, 174 buf, buflen, adom, FM_FMRI_AUTH_DOMAIN "=", 175 --more_auth > 0 ? "," : NULL); 176 if (asrvr != NULL) 177 topo_fmristr_build(&size, 178 buf, buflen, asrvr, FM_FMRI_AUTH_SERVER "=", 179 --more_auth > 0 ? "," : NULL); 180 if (ahost != NULL) 181 topo_fmristr_build(&size, 182 buf, buflen, ahost, FM_FMRI_AUTH_HOST "=", 183 NULL); 184 185 /* device-id part, topo_fmristr_build does nothing if devid is NULL */ 186 topo_fmristr_build(&size, 187 buf, buflen, devid, "/:" FM_FMRI_DEV_ID "=", NULL); 188 189 /* device-path part */ 190 topo_fmristr_build(&size, buf, buflen, devpath, "/", NULL); 191 192 return (size); 193 } 194 195 /*ARGSUSED*/ 196 static int 197 dev_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 198 nvlist_t *nvl, nvlist_t **out) 199 { 200 ssize_t len; 201 char *name = NULL; 202 nvlist_t *fmristr; 203 204 if (version > TOPO_METH_NVL2STR_VERSION) 205 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 206 207 if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 || 208 (name = topo_mod_alloc(mod, len + 1)) == NULL || 209 fmri_nvl2str(nvl, name, len + 1) == 0) { 210 if (name != NULL) 211 topo_mod_free(mod, name, len + 1); 212 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 213 } 214 215 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) 216 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 217 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 218 topo_mod_free(mod, name, len + 1); 219 nvlist_free(fmristr); 220 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 221 } 222 topo_mod_free(mod, name, len + 1); 223 *out = fmristr; 224 225 return (0); 226 } 227 228 /*ARGSUSED*/ 229 static int 230 dev_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 231 nvlist_t *in, nvlist_t **out) 232 { 233 nvlist_t *fmri; 234 char *devpath; 235 char *devid = NULL; 236 char *str; 237 int err; 238 239 if (version > TOPO_METH_STR2NVL_VERSION) 240 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 241 242 if (nvlist_lookup_string(in, "fmri-string", &str) != 0) 243 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 244 245 /* We're expecting a string version of a dev scheme FMRI */ 246 if (strncmp(str, "dev:///", 7) != 0) 247 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 248 249 devpath = str + 7; 250 if (strncmp(devpath, ":" FM_FMRI_DEV_ID "=", 7) == 0) { 251 char *n; 252 int len; 253 254 n = strchr(devpath + 7, '/'); 255 if (n == NULL) 256 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 257 len = n - (devpath + 7); 258 devid = alloca(len + 1); 259 (void) memcpy(devid, devpath + 7, len); 260 devid[len] = 0; 261 devpath = n + 1; 262 } 263 264 /* the device-path should start with a slash */ 265 if (*devpath != '/') 266 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 267 268 if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 269 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 270 271 err = nvlist_add_uint8(fmri, FM_VERSION, FM_DEV_SCHEME_VERSION); 272 err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV); 273 err |= nvlist_add_string(fmri, FM_FMRI_DEV_PATH, devpath); 274 if (devid != NULL) 275 err |= nvlist_add_string(fmri, FM_FMRI_DEV_ID, devid); 276 277 if (err != 0) { 278 nvlist_free(fmri); 279 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 280 } 281 *out = fmri; 282 283 return (0); 284 } 285 286 static nvlist_t * 287 dev_fmri_create(topo_mod_t *mp, const char *id, const char *path) 288 { 289 nvlist_t *out = NULL; 290 int e; 291 292 if (topo_mod_nvalloc(mp, &out, NV_UNIQUE_NAME) != 0) { 293 (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); 294 return (NULL); 295 } 296 e = nvlist_add_string(out, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV); 297 e |= nvlist_add_uint8(out, FM_VERSION, FM_DEV_SCHEME_VERSION); 298 e |= nvlist_add_string(out, FM_FMRI_DEV_PATH, path); 299 300 if (id != NULL) 301 e |= nvlist_add_string(out, FM_FMRI_DEV_ID, id); 302 303 if (e == 0) 304 return (out); 305 306 topo_mod_dprintf(mp, "construction of dev nvl failed"); 307 (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); 308 nvlist_free(out); 309 return (NULL); 310 } 311 312 /*ARGSUSED*/ 313 static int 314 dev_fmri_create_meth(topo_mod_t *mp, tnode_t *node, topo_version_t version, 315 nvlist_t *in, nvlist_t **out) 316 { 317 nvlist_t *args = NULL; 318 char *path, *id = NULL; 319 320 if (version > TOPO_METH_FMRI_VERSION) 321 return (topo_mod_seterrno(mp, EMOD_VER_NEW)); 322 323 if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args) != 0 || 324 nvlist_lookup_string(args, FM_FMRI_DEV_PATH, &path) != 0) { 325 topo_mod_dprintf(mp, "no path string in method argument\n"); 326 return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); 327 } 328 329 (void) nvlist_lookup_string(args, FM_FMRI_DEV_ID, &id); 330 331 if ((*out = dev_fmri_create(mp, id, path)) == NULL) 332 return (-1); 333 return (0); 334 } 335