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