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