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