1 /* 2 * 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <ctype.h> 35 #include <alloca.h> 36 #include <limits.h> 37 #include <fm/topo_mod.h> 38 #include <sys/param.h> 39 #include <sys/systeminfo.h> 40 #include <sys/fm/protocol.h> 41 #include <sys/stat.h> 42 43 #include <topo_method.h> 44 #include <topo_subr.h> 45 #include <legacy_hc.h> 46 47 static int legacy_hc_enum(topo_mod_t *, tnode_t *, const char *, 48 topo_instance_t, topo_instance_t, void *, void *); 49 static void legacy_hc_release(topo_mod_t *, tnode_t *); 50 static int legacy_hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 51 nvlist_t *, nvlist_t **); 52 53 const topo_method_t legacy_hc_methods[] = { 54 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 55 TOPO_STABILITY_INTERNAL, legacy_hc_fmri_nvl2str }, 56 { NULL } 57 }; 58 59 static const topo_modops_t legacy_hc_ops = 60 { legacy_hc_enum, legacy_hc_release }; 61 static const topo_modinfo_t legacy_hc_info = 62 { LEGACY_HC, FM_FMRI_SCHEME_LEGACY, LEGACY_HC_VERSION, &legacy_hc_ops }; 63 64 int 65 legacy_hc_init(topo_mod_t *mod, topo_version_t version) 66 { 67 /* 68 * Turn on module debugging output 69 */ 70 if (getenv("TOPOLEGACY_HCDEBUG")) 71 topo_mod_setdebug(mod); 72 73 topo_mod_dprintf(mod, "initializing legacy_hc builtin\n"); 74 75 if (version != LEGACY_HC_VERSION) 76 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 77 78 if (topo_mod_register(mod, &legacy_hc_info, TOPO_VERSION) != 0) { 79 topo_mod_dprintf(mod, "failed to register legacy_hc: " 80 "%s\n", topo_mod_errmsg(mod)); 81 return (-1); /* mod errno already set */ 82 } 83 84 return (0); 85 } 86 87 void 88 legacy_hc_fini(topo_mod_t *mod) 89 { 90 topo_mod_unregister(mod); 91 } 92 93 94 /*ARGSUSED*/ 95 int 96 legacy_hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 97 topo_instance_t min, topo_instance_t max, void *notused1, void *notused2) 98 { 99 (void) topo_method_register(mod, pnode, legacy_hc_methods); 100 return (0); 101 } 102 103 /*ARGSUSED*/ 104 static void 105 legacy_hc_release(topo_mod_t *mp, tnode_t *node) 106 { 107 topo_method_unregister_all(mp, node); 108 } 109 110 /* 111 * Convert an input string to a URI escaped string and return the new string. 112 * RFC2396 Section 2.4 says that data must be escaped if it does not have a 113 * representation using an unreserved character, where an unreserved character 114 * is one that is either alphanumeric or one of the marks defined in S2.3. 115 */ 116 static size_t 117 mem_fmri_uriescape(const char *s, const char *xmark, char *buf, size_t len) 118 { 119 static const char rfc2396_mark[] = "-_.!~*'()"; 120 static const char hex_digits[] = "0123456789ABCDEF"; 121 static const char empty_str[] = ""; 122 123 const char *p; 124 char c, *q; 125 size_t n = 0; 126 127 if (s == NULL) 128 s = empty_str; 129 130 if (xmark == NULL) 131 xmark = empty_str; 132 133 for (p = s; (c = *p) != '\0'; p++) { 134 if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c)) 135 n++; /* represent c as itself */ 136 else 137 n += 3; /* represent c as escape */ 138 } 139 140 if (buf == NULL) 141 return (n); 142 143 for (p = s, q = buf; (c = *p) != '\0' && q < buf + len; p++) { 144 if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c)) { 145 *q++ = c; 146 } else { 147 *q++ = '%'; 148 *q++ = hex_digits[((uchar_t)c & 0xf0) >> 4]; 149 *q++ = hex_digits[(uchar_t)c & 0xf]; 150 } 151 } 152 153 if (q == buf + len) 154 q--; /* len is too small: truncate output string */ 155 156 *q = '\0'; 157 return (n); 158 } 159 160 static ssize_t 161 fmri_nvl2str(topo_mod_t *mod, nvlist_t *nvl, char *buf, size_t buflen) 162 { 163 uint8_t version; 164 ssize_t size; 165 char *c; 166 char *escc; 167 int i; 168 169 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 170 version > FM_LEGACY_SCHEME_VERSION || 171 nvlist_lookup_string(nvl, FM_FMRI_LEGACY_HC, &c) != 0) 172 return (0); 173 174 i = mem_fmri_uriescape(c, ":,/", NULL, 0); 175 escc = topo_mod_alloc(mod, i + 1); 176 (void) mem_fmri_uriescape(c, ":,/", escc, i + 1); 177 size = snprintf(buf, buflen, "legacy-hc:///component=%s", escc); 178 topo_mod_free(mod, escc, i + 1); 179 180 return (size); 181 } 182 183 /*ARGSUSED*/ 184 static int 185 legacy_hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 186 nvlist_t *nvl, nvlist_t **out) 187 { 188 ssize_t len; 189 char *name = NULL; 190 nvlist_t *fmristr; 191 192 if (version > TOPO_METH_NVL2STR_VERSION) 193 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 194 195 if ((len = fmri_nvl2str(mod, nvl, NULL, 0)) == 0 || 196 (name = topo_mod_alloc(mod, len + 1)) == NULL || 197 fmri_nvl2str(mod, nvl, name, len + 1) == 0) { 198 if (name != NULL) 199 topo_mod_free(mod, name, len + 1); 200 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 201 } 202 203 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) { 204 topo_mod_free(mod, name, len + 1); 205 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 206 } 207 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 208 topo_mod_free(mod, name, len + 1); 209 nvlist_free(fmristr); 210 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 211 } 212 topo_mod_free(mod, name, len + 1); 213 *out = fmristr; 214 215 return (0); 216 } 217