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 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <errno.h> 32 #include <ctype.h> 33 #include <alloca.h> 34 #include <limits.h> 35 #include <fm/topo_mod.h> 36 #include <sys/param.h> 37 #include <sys/systeminfo.h> 38 #include <sys/fm/protocol.h> 39 #include <sys/stat.h> 40 41 #include <topo_method.h> 42 #include <topo_subr.h> 43 #include <legacy_hc.h> 44 45 static int legacy_hc_enum(topo_mod_t *, tnode_t *, const char *, 46 topo_instance_t, topo_instance_t, void *, void *); 47 static void legacy_hc_release(topo_mod_t *, tnode_t *); 48 static int legacy_hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 49 nvlist_t *, nvlist_t **); 50 51 const topo_method_t legacy_hc_methods[] = { 52 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 53 TOPO_STABILITY_INTERNAL, legacy_hc_fmri_nvl2str }, 54 { NULL } 55 }; 56 57 static const topo_modops_t legacy_hc_ops = 58 { legacy_hc_enum, legacy_hc_release }; 59 static const topo_modinfo_t legacy_hc_info = 60 { LEGACY_HC, FM_FMRI_SCHEME_LEGACY, LEGACY_HC_VERSION, &legacy_hc_ops }; 61 62 int 63 legacy_hc_init(topo_mod_t *mod, topo_version_t version) 64 { 65 /* 66 * Turn on module debugging output 67 */ 68 if (getenv("TOPOLEGACY_HCDEBUG")) 69 topo_mod_setdebug(mod); 70 71 topo_mod_dprintf(mod, "initializing legacy_hc builtin\n"); 72 73 if (version != LEGACY_HC_VERSION) 74 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 75 76 if (topo_mod_register(mod, &legacy_hc_info, TOPO_VERSION) != 0) { 77 topo_mod_dprintf(mod, "failed to register legacy_hc: " 78 "%s\n", topo_mod_errmsg(mod)); 79 return (-1); /* mod errno already set */ 80 } 81 82 return (0); 83 } 84 85 void 86 legacy_hc_fini(topo_mod_t *mod) 87 { 88 topo_mod_unregister(mod); 89 } 90 91 92 /*ARGSUSED*/ 93 int 94 legacy_hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 95 topo_instance_t min, topo_instance_t max, void *notused1, void *notused2) 96 { 97 (void) topo_method_register(mod, pnode, legacy_hc_methods); 98 return (0); 99 } 100 101 /*ARGSUSED*/ 102 static void 103 legacy_hc_release(topo_mod_t *mp, tnode_t *node) 104 { 105 topo_method_unregister_all(mp, node); 106 } 107 108 /* 109 * Convert an input string to a URI escaped string and return the new string. 110 * RFC2396 Section 2.4 says that data must be escaped if it does not have a 111 * representation using an unreserved character, where an unreserved character 112 * is one that is either alphanumeric or one of the marks defined in S2.3. 113 */ 114 static size_t 115 mem_fmri_uriescape(const char *s, const char *xmark, char *buf, size_t len) 116 { 117 static const char rfc2396_mark[] = "-_.!~*'()"; 118 static const char hex_digits[] = "0123456789ABCDEF"; 119 static const char empty_str[] = ""; 120 121 const char *p; 122 char c, *q; 123 size_t n = 0; 124 125 if (s == NULL) 126 s = empty_str; 127 128 if (xmark == NULL) 129 xmark = empty_str; 130 131 for (p = s; (c = *p) != '\0'; p++) { 132 if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c)) 133 n++; /* represent c as itself */ 134 else 135 n += 3; /* represent c as escape */ 136 } 137 138 if (buf == NULL) 139 return (n); 140 141 for (p = s, q = buf; (c = *p) != '\0' && q < buf + len; p++) { 142 if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c)) { 143 *q++ = c; 144 } else { 145 *q++ = '%'; 146 *q++ = hex_digits[((uchar_t)c & 0xf0) >> 4]; 147 *q++ = hex_digits[(uchar_t)c & 0xf]; 148 } 149 } 150 151 if (q == buf + len) 152 q--; /* len is too small: truncate output string */ 153 154 *q = '\0'; 155 return (n); 156 } 157 158 static ssize_t 159 fmri_nvl2str(topo_mod_t *mod, nvlist_t *nvl, char *buf, size_t buflen) 160 { 161 uint8_t version; 162 ssize_t size; 163 char *c; 164 char *escc; 165 int i; 166 167 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 168 version > FM_LEGACY_SCHEME_VERSION || 169 nvlist_lookup_string(nvl, FM_FMRI_LEGACY_HC, &c) != 0) 170 return (0); 171 172 i = mem_fmri_uriescape(c, ":,/", NULL, 0); 173 escc = topo_mod_alloc(mod, i + 1); 174 (void) mem_fmri_uriescape(c, ":,/", escc, i + 1); 175 size = snprintf(buf, buflen, "legacy-hc:///component=%s", escc); 176 topo_mod_free(mod, escc, i + 1); 177 178 return (size); 179 } 180 181 /*ARGSUSED*/ 182 static int 183 legacy_hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 184 nvlist_t *nvl, nvlist_t **out) 185 { 186 ssize_t len; 187 char *name = NULL; 188 nvlist_t *fmristr; 189 190 if (version > TOPO_METH_NVL2STR_VERSION) 191 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 192 193 if ((len = fmri_nvl2str(mod, nvl, NULL, 0)) == 0 || 194 (name = topo_mod_alloc(mod, len + 1)) == NULL || 195 fmri_nvl2str(mod, nvl, name, len + 1) == 0) { 196 if (name != NULL) 197 topo_mod_free(mod, name, len + 1); 198 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 199 } 200 201 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) { 202 topo_mod_free(mod, name, len + 1); 203 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 204 } 205 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 206 topo_mod_free(mod, name, len + 1); 207 nvlist_free(fmristr); 208 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 209 } 210 topo_mod_free(mod, name, len + 1); 211 *out = fmristr; 212 213 return (0); 214 } 215