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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * 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 2006 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 <ctype.h> 31 #include <errno.h> 32 #include <stdarg.h> 33 34 #include <fmd_alloc.h> 35 #include <fmd_subr.h> 36 #include <fmd_error.h> 37 #include <fmd_string.h> 38 #include <fmd_scheme.h> 39 #include <fmd_fmri.h> 40 #include <fmd.h> 41 42 #include <fm/libtopo.h> 43 44 /* 45 * Interfaces to be used by the plugins 46 */ 47 48 void * 49 fmd_fmri_alloc(size_t size) 50 { 51 return (fmd_alloc(size, FMD_SLEEP)); 52 } 53 54 void * 55 fmd_fmri_zalloc(size_t size) 56 { 57 return (fmd_zalloc(size, FMD_SLEEP)); 58 } 59 60 void 61 fmd_fmri_free(void *data, size_t size) 62 { 63 fmd_free(data, size); 64 } 65 66 int 67 fmd_fmri_set_errno(int err) 68 { 69 errno = err; 70 return (-1); 71 } 72 73 void 74 fmd_fmri_warn(const char *format, ...) 75 { 76 va_list ap; 77 78 va_start(ap, format); 79 fmd_verror(EFMD_FMRI_SCHEME, format, ap); 80 va_end(ap); 81 } 82 83 /* 84 * Convert an input string to a URI escaped string and return the new string. 85 * RFC2396 Section 2.4 says that data must be escaped if it does not have a 86 * representation using an unreserved character, where an unreserved character 87 * is one that is either alphanumberic or one of the marks defined in S2.3. 88 */ 89 static size_t 90 fmd_fmri_uriescape(const char *s, const char *xmark, char *buf, size_t len) 91 { 92 static const char rfc2396_mark[] = "-_.!~*'()"; 93 static const char hex_digits[] = "0123456789ABCDEF"; 94 static const char empty_str[] = ""; 95 96 const char *p; 97 char c, *q; 98 size_t n = 0; 99 100 if (s == NULL) 101 s = empty_str; 102 103 if (xmark == NULL) 104 xmark = empty_str; 105 106 for (p = s; (c = *p) != '\0'; p++) { 107 if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c)) 108 n++; /* represent c as itself */ 109 else 110 n += 3; /* represent c as escape */ 111 } 112 113 if (buf == NULL) 114 return (n); 115 116 for (p = s, q = buf; (c = *p) != '\0' && q < buf + len; p++) { 117 if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c)) { 118 *q++ = c; 119 } else { 120 *q++ = '%'; 121 *q++ = hex_digits[((uchar_t)c & 0xf0) >> 4]; 122 *q++ = hex_digits[(uchar_t)c & 0xf]; 123 } 124 } 125 126 if (q == buf + len) 127 q--; /* len is too small: truncate output string */ 128 129 *q = '\0'; 130 return (n); 131 } 132 133 /* 134 * Convert a name-value pair list representing an FMRI authority into the 135 * corresponding RFC2396 string representation and return the new string. 136 */ 137 char * 138 fmd_fmri_auth2str(nvlist_t *nvl) 139 { 140 nvpair_t *nvp; 141 char *s, *p, *v; 142 size_t n = 0; 143 144 for (nvp = nvlist_next_nvpair(nvl, NULL); 145 nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) { 146 147 if (nvpair_type(nvp) != DATA_TYPE_STRING) 148 continue; /* do not format non-string elements */ 149 150 n += fmd_fmri_uriescape(nvpair_name(nvp), NULL, NULL, 0) + 1; 151 (void) nvpair_value_string(nvp, &v); 152 n += fmd_fmri_uriescape(v, ":", NULL, 0) + 1; 153 } 154 155 p = s = fmd_alloc(n, FMD_SLEEP); 156 157 for (nvp = nvlist_next_nvpair(nvl, NULL); 158 nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) { 159 160 if (nvpair_type(nvp) != DATA_TYPE_STRING) 161 continue; /* do not format non-string elements */ 162 163 if (p != s) 164 *p++ = ','; 165 166 p += fmd_fmri_uriescape(nvpair_name(nvp), NULL, p, n); 167 *p++ = '='; 168 (void) nvpair_value_string(nvp, &v); 169 p += fmd_fmri_uriescape(v, ":", p, n); 170 } 171 172 return (s); 173 } 174 175 /* 176 * Convert an input string to a URI escaped string and return the new string. 177 * We amend the unreserved character list to include commas and colons, 178 * as both are needed to make FMRIs readable without escaping. We also permit 179 * "/" to pass through unescaped as any path delimiters used by the event 180 * creator are presumably intended to appear in the final path. 181 */ 182 char * 183 fmd_fmri_strescape(const char *s) 184 { 185 char *s2; 186 size_t n; 187 188 if (s == NULL) 189 return (NULL); 190 191 n = fmd_fmri_uriescape(s, ":,/", NULL, 0); 192 s2 = fmd_alloc(n + 1, FMD_SLEEP); 193 (void) fmd_fmri_uriescape(s, ":,/", s2, n + 1); 194 195 return (s2); 196 } 197 198 char * 199 fmd_fmri_strdup(const char *s) 200 { 201 return (fmd_strdup(s, FMD_SLEEP)); 202 } 203 204 void 205 fmd_fmri_strfree(char *s) 206 { 207 fmd_strfree(s); 208 } 209 210 const char * 211 fmd_fmri_get_rootdir(void) 212 { 213 return (fmd.d_rootdir); 214 } 215 216 const char * 217 fmd_fmri_get_platform(void) 218 { 219 return (fmd.d_platform); 220 } 221 222 uint64_t 223 fmd_fmri_get_drgen(void) 224 { 225 uint64_t gen; 226 227 (void) pthread_mutex_lock(&fmd.d_stats_lock); 228 gen = fmd.d_stats->ds_dr_gen.fmds_value.ui64; 229 (void) pthread_mutex_unlock(&fmd.d_stats_lock); 230 231 return (gen); 232 } 233 234 struct topo_hdl * 235 fmd_fmri_topology(int version) 236 { 237 ASSERT(version == TOPO_VERSION); 238 return (fmd.d_topo); 239 } 240 241 /* 242 * Interfaces for users of the plugins 243 */ 244 245 static fmd_scheme_t * 246 nvl2scheme(nvlist_t *nvl) 247 { 248 char *name; 249 250 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) { 251 (void) fmd_set_errno(EFMD_FMRI_INVAL); 252 return (NULL); 253 } 254 255 return (fmd_scheme_hash_lookup(fmd.d_schemes, name)); 256 } 257 258 ssize_t 259 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 260 { 261 fmd_scheme_t *sp; 262 char c; 263 ssize_t rv; 264 265 if (buf == NULL && buflen == 0) { 266 buf = &c; 267 buflen = sizeof (c); 268 } 269 270 if ((sp = nvl2scheme(nvl)) == NULL) 271 return (-1); /* errno is set for us */ 272 273 (void) pthread_mutex_lock(&sp->sch_opslock); 274 ASSERT(buf != NULL || buflen == 0); 275 rv = sp->sch_ops.sop_nvl2str(nvl, buf, buflen); 276 (void) pthread_mutex_unlock(&sp->sch_opslock); 277 278 fmd_scheme_hash_release(fmd.d_schemes, sp); 279 return (rv); 280 } 281 282 int 283 fmd_fmri_expand(nvlist_t *nvl) 284 { 285 fmd_scheme_t *sp; 286 int rv; 287 288 if ((sp = nvl2scheme(nvl)) == NULL) 289 return (-1); /* errno is set for us */ 290 291 (void) pthread_mutex_lock(&sp->sch_opslock); 292 rv = sp->sch_ops.sop_expand(nvl); 293 (void) pthread_mutex_unlock(&sp->sch_opslock); 294 295 fmd_scheme_hash_release(fmd.d_schemes, sp); 296 return (rv); 297 } 298 299 int 300 fmd_fmri_present(nvlist_t *nvl) 301 { 302 fmd_scheme_t *sp; 303 int rv; 304 305 if ((sp = nvl2scheme(nvl)) == NULL) 306 return (-1); /* errno is set for us */ 307 308 (void) pthread_mutex_lock(&sp->sch_opslock); 309 rv = sp->sch_ops.sop_present(nvl); 310 (void) pthread_mutex_unlock(&sp->sch_opslock); 311 312 fmd_scheme_hash_release(fmd.d_schemes, sp); 313 return (rv); 314 } 315 316 int 317 fmd_fmri_unusable(nvlist_t *nvl) 318 { 319 fmd_scheme_t *sp; 320 int rv; 321 322 if ((sp = nvl2scheme(nvl)) == NULL) 323 return (-1); /* errno is set for us */ 324 325 (void) pthread_mutex_lock(&sp->sch_opslock); 326 rv = sp->sch_ops.sop_unusable(nvl); 327 (void) pthread_mutex_unlock(&sp->sch_opslock); 328 329 fmd_scheme_hash_release(fmd.d_schemes, sp); 330 return (rv); 331 } 332 333 int 334 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) 335 { 336 fmd_scheme_t *sp; 337 char *ername, *eename; 338 int rv; 339 340 if (nvlist_lookup_string(er, FM_FMRI_SCHEME, &ername) != 0 || 341 nvlist_lookup_string(ee, FM_FMRI_SCHEME, &eename) != 0 || 342 strcmp(ername, eename) != 0) 343 return (fmd_set_errno(EFMD_FMRI_INVAL)); 344 345 if ((sp = fmd_scheme_hash_lookup(fmd.d_schemes, ername)) == NULL) 346 return (-1); /* errno is set for us */ 347 348 (void) pthread_mutex_lock(&sp->sch_opslock); 349 rv = sp->sch_ops.sop_contains(er, ee); 350 (void) pthread_mutex_unlock(&sp->sch_opslock); 351 352 fmd_scheme_hash_release(fmd.d_schemes, sp); 353 return (rv); 354 } 355 356 nvlist_t * 357 fmd_fmri_translate(nvlist_t *fmri, nvlist_t *auth) 358 { 359 fmd_scheme_t *sp; 360 nvlist_t *nvl; 361 362 if ((sp = nvl2scheme(fmri)) == NULL) 363 return (NULL); /* errno is set for us */ 364 365 (void) pthread_mutex_lock(&sp->sch_opslock); 366 nvl = sp->sch_ops.sop_translate(fmri, auth); 367 (void) pthread_mutex_unlock(&sp->sch_opslock); 368 369 fmd_scheme_hash_release(fmd.d_schemes, sp); 370 return (nvl); 371 } 372