/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include /* * Interfaces to be used by the plugins */ void * fmd_fmri_alloc(size_t size) { return (fmd_alloc(size, FMD_SLEEP)); } void * fmd_fmri_zalloc(size_t size) { return (fmd_zalloc(size, FMD_SLEEP)); } void fmd_fmri_free(void *data, size_t size) { fmd_free(data, size); } int fmd_fmri_set_errno(int err) { errno = err; return (-1); } void fmd_fmri_warn(const char *format, ...) { va_list ap; va_start(ap, format); fmd_verror(EFMD_FMRI_SCHEME, format, ap); va_end(ap); } /* * Convert an input string to a URI escaped string and return the new string. * RFC2396 Section 2.4 says that data must be escaped if it does not have a * representation using an unreserved character, where an unreserved character * is one that is either alphanumeric or one of the marks defined in S2.3. */ static size_t fmd_fmri_uriescape(const char *s, const char *xmark, char *buf, size_t len) { static const char rfc2396_mark[] = "-_.!~*'()"; static const char hex_digits[] = "0123456789ABCDEF"; static const char empty_str[] = ""; const char *p; char c, *q; size_t n = 0; if (s == NULL) s = empty_str; if (xmark == NULL) xmark = empty_str; for (p = s; (c = *p) != '\0'; p++) { if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c)) n++; /* represent c as itself */ else n += 3; /* represent c as escape */ } if (buf == NULL) return (n); for (p = s, q = buf; (c = *p) != '\0' && q < buf + len; p++) { if (isalnum(c) || strchr(rfc2396_mark, c) || strchr(xmark, c)) { *q++ = c; } else { *q++ = '%'; *q++ = hex_digits[((uchar_t)c & 0xf0) >> 4]; *q++ = hex_digits[(uchar_t)c & 0xf]; } } if (q == buf + len) q--; /* len is too small: truncate output string */ *q = '\0'; return (n); } /* * Convert a name-value pair list representing an FMRI authority into the * corresponding RFC2396 string representation and return the new string. */ char * fmd_fmri_auth2str(nvlist_t *nvl) { nvpair_t *nvp; char *s, *p, *v; size_t n = 0; for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) { if (nvpair_type(nvp) != DATA_TYPE_STRING) continue; /* do not format non-string elements */ n += fmd_fmri_uriescape(nvpair_name(nvp), NULL, NULL, 0) + 1; (void) nvpair_value_string(nvp, &v); n += fmd_fmri_uriescape(v, ":", NULL, 0) + 1; } p = s = fmd_alloc(n, FMD_SLEEP); for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) { if (nvpair_type(nvp) != DATA_TYPE_STRING) continue; /* do not format non-string elements */ if (p != s) *p++ = ','; p += fmd_fmri_uriescape(nvpair_name(nvp), NULL, p, n); *p++ = '='; (void) nvpair_value_string(nvp, &v); p += fmd_fmri_uriescape(v, ":", p, n); } return (s); } /* * Convert an input string to a URI escaped string and return the new string. * We amend the unreserved character list to include commas and colons, * as both are needed to make FMRIs readable without escaping. We also permit * "/" to pass through unescaped as any path delimiters used by the event * creator are presumably intended to appear in the final path. */ char * fmd_fmri_strescape(const char *s) { char *s2; size_t n; if (s == NULL) return (NULL); n = fmd_fmri_uriescape(s, ":,/", NULL, 0); s2 = fmd_alloc(n + 1, FMD_SLEEP); (void) fmd_fmri_uriescape(s, ":,/", s2, n + 1); return (s2); } char * fmd_fmri_strdup(const char *s) { return (fmd_strdup(s, FMD_SLEEP)); } void fmd_fmri_strfree(char *s) { fmd_strfree(s); } const char * fmd_fmri_get_rootdir(void) { return (fmd.d_rootdir); } const char * fmd_fmri_get_platform(void) { return (fmd.d_platform); } uint64_t fmd_fmri_get_drgen(void) { uint64_t gen; (void) pthread_mutex_lock(&fmd.d_stats_lock); gen = fmd.d_stats->ds_dr_gen.fmds_value.ui64; (void) pthread_mutex_unlock(&fmd.d_stats_lock); return (gen); } struct topo_hdl * fmd_fmri_topo_hold(int version) { fmd_topo_t *ftp; if (version != TOPO_VERSION) return (NULL); ftp = fmd_topo_hold(); return (ftp->ft_hdl); } void fmd_fmri_topo_rele(struct topo_hdl *thp) { fmd_topo_rele_hdl(thp); } /* * Interfaces for users of the plugins */ static fmd_scheme_t * nvl2scheme(nvlist_t *nvl) { char *name; if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) { (void) fmd_set_errno(EFMD_FMRI_INVAL); return (NULL); } return (fmd_scheme_hash_lookup(fmd.d_schemes, name)); } ssize_t fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) { fmd_scheme_t *sp; char c; ssize_t rv; if (buf == NULL && buflen == 0) { buf = &c; buflen = sizeof (c); } if ((sp = nvl2scheme(nvl)) == NULL) return (-1); /* errno is set for us */ (void) pthread_mutex_lock(&sp->sch_opslock); ASSERT(buf != NULL || buflen == 0); rv = sp->sch_ops.sop_nvl2str(nvl, buf, buflen); (void) pthread_mutex_unlock(&sp->sch_opslock); fmd_scheme_hash_release(fmd.d_schemes, sp); return (rv); } int fmd_fmri_expand(nvlist_t *nvl) { fmd_scheme_t *sp; int rv; if ((sp = nvl2scheme(nvl)) == NULL) return (-1); /* errno is set for us */ (void) pthread_mutex_lock(&sp->sch_opslock); rv = sp->sch_ops.sop_expand(nvl); (void) pthread_mutex_unlock(&sp->sch_opslock); fmd_scheme_hash_release(fmd.d_schemes, sp); return (rv); } int fmd_fmri_present(nvlist_t *nvl) { fmd_scheme_t *sp; int rv; if ((sp = nvl2scheme(nvl)) == NULL) return (-1); /* errno is set for us */ (void) pthread_mutex_lock(&sp->sch_opslock); rv = sp->sch_ops.sop_present(nvl); (void) pthread_mutex_unlock(&sp->sch_opslock); fmd_scheme_hash_release(fmd.d_schemes, sp); return (rv); } int fmd_fmri_replaced(nvlist_t *nvl) { fmd_scheme_t *sp; int rv; if ((sp = nvl2scheme(nvl)) == NULL) return (-1); /* errno is set for us */ (void) pthread_mutex_lock(&sp->sch_opslock); rv = sp->sch_ops.sop_replaced(nvl); (void) pthread_mutex_unlock(&sp->sch_opslock); fmd_scheme_hash_release(fmd.d_schemes, sp); return (rv); } int fmd_fmri_service_state(nvlist_t *nvl) { fmd_scheme_t *sp; int rv; if ((sp = nvl2scheme(nvl)) == NULL) return (-1); /* errno is set for us */ (void) pthread_mutex_lock(&sp->sch_opslock); rv = sp->sch_ops.sop_service_state(nvl); (void) pthread_mutex_unlock(&sp->sch_opslock); fmd_scheme_hash_release(fmd.d_schemes, sp); return (rv); } int fmd_fmri_unusable(nvlist_t *nvl) { fmd_scheme_t *sp; int rv; if ((sp = nvl2scheme(nvl)) == NULL) return (-1); /* errno is set for us */ (void) pthread_mutex_lock(&sp->sch_opslock); rv = sp->sch_ops.sop_unusable(nvl); (void) pthread_mutex_unlock(&sp->sch_opslock); fmd_scheme_hash_release(fmd.d_schemes, sp); return (rv); } /* * Someday we'll retire the scheme plugins. For the * retire/unretire operations, the topo interfaces * are called directly. */ int fmd_fmri_retire(nvlist_t *nvl) { topo_hdl_t *thp; int rv, err; if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) return (-1); rv = topo_fmri_retire(thp, nvl, &err); fmd_fmri_topo_rele(thp); return (rv); } int fmd_fmri_unretire(nvlist_t *nvl) { topo_hdl_t *thp; int rv, err; if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) return (-1); rv = topo_fmri_unretire(thp, nvl, &err); fmd_fmri_topo_rele(thp); return (rv); } int fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) { fmd_scheme_t *sp; char *ername, *eename; int rv; if (nvlist_lookup_string(er, FM_FMRI_SCHEME, &ername) != 0 || nvlist_lookup_string(ee, FM_FMRI_SCHEME, &eename) != 0 || strcmp(ername, eename) != 0) return (fmd_set_errno(EFMD_FMRI_INVAL)); if ((sp = fmd_scheme_hash_lookup(fmd.d_schemes, ername)) == NULL) return (-1); /* errno is set for us */ (void) pthread_mutex_lock(&sp->sch_opslock); rv = sp->sch_ops.sop_contains(er, ee); (void) pthread_mutex_unlock(&sp->sch_opslock); fmd_scheme_hash_release(fmd.d_schemes, sp); return (rv); } nvlist_t * fmd_fmri_translate(nvlist_t *fmri, nvlist_t *auth) { fmd_scheme_t *sp; nvlist_t *nvl; if ((sp = nvl2scheme(fmri)) == NULL) return (NULL); /* errno is set for us */ (void) pthread_mutex_lock(&sp->sch_opslock); nvl = sp->sch_ops.sop_translate(fmri, auth); (void) pthread_mutex_unlock(&sp->sch_opslock); fmd_scheme_hash_release(fmd.d_schemes, sp); return (nvl); }