17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
519e1255fScy152378 * Common Development and Distribution License (the "License").
619e1255fScy152378 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21d9638e54Smws
227c478bd9Sstevel@tonic-gate /*
23e58a33b6SStephen Hanson * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include <limits.h>
277c478bd9Sstevel@tonic-gate #include <stddef.h>
287c478bd9Sstevel@tonic-gate #include <unistd.h>
297c478bd9Sstevel@tonic-gate #include <dlfcn.h>
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate #include <fmd_alloc.h>
327c478bd9Sstevel@tonic-gate #include <fmd_error.h>
337c478bd9Sstevel@tonic-gate #include <fmd_subr.h>
347c478bd9Sstevel@tonic-gate #include <fmd_string.h>
357c478bd9Sstevel@tonic-gate #include <fmd_scheme.h>
367c478bd9Sstevel@tonic-gate #include <fmd_fmri.h>
377c478bd9Sstevel@tonic-gate #include <fmd_module.h>
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #include <fmd.h>
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate * The fmd resource scheme, used for fmd modules, must be implemented here for
437c478bd9Sstevel@tonic-gate * the benefit of fmd-self-diagnosis and also in schemes/fmd for fmdump(1M).
447c478bd9Sstevel@tonic-gate */
457c478bd9Sstevel@tonic-gate ssize_t
fmd_scheme_fmd_nvl2str(nvlist_t * nvl,char * buf,size_t buflen)467c478bd9Sstevel@tonic-gate fmd_scheme_fmd_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate char *name;
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(nvl, FM_FMRI_FMD_NAME, &name) != 0)
517c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL));
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate return (snprintf(buf, buflen,
547c478bd9Sstevel@tonic-gate "%s:///module/%s", FM_FMRI_SCHEME_FMD, name));
557c478bd9Sstevel@tonic-gate }
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate static int
fmd_scheme_fmd_present(nvlist_t * nvl)587c478bd9Sstevel@tonic-gate fmd_scheme_fmd_present(nvlist_t *nvl)
597c478bd9Sstevel@tonic-gate {
607c478bd9Sstevel@tonic-gate char *name, *version;
617c478bd9Sstevel@tonic-gate fmd_module_t *mp;
62e58a33b6SStephen Hanson int rv = 1;
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(nvl, FM_FMRI_FMD_NAME, &name) != 0 ||
657c478bd9Sstevel@tonic-gate nvlist_lookup_string(nvl, FM_FMRI_FMD_VERSION, &version) != 0)
667c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL));
677c478bd9Sstevel@tonic-gate
68*35f59e50SStephen Hanson if (!fmd.d_loaded)
69*35f59e50SStephen Hanson return (1);
70*35f59e50SStephen Hanson
717c478bd9Sstevel@tonic-gate if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) != NULL) {
7219e1255fScy152378 rv = mp->mod_vers != NULL &&
7319e1255fScy152378 strcmp(mp->mod_vers, version) == 0;
747c478bd9Sstevel@tonic-gate fmd_module_rele(mp);
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate return (rv);
787c478bd9Sstevel@tonic-gate }
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate static int
fmd_scheme_fmd_replaced(nvlist_t * nvl)8125c6ff4bSstephh fmd_scheme_fmd_replaced(nvlist_t *nvl)
8225c6ff4bSstephh {
8325c6ff4bSstephh char *name, *version;
8425c6ff4bSstephh fmd_module_t *mp;
85e58a33b6SStephen Hanson int rv = 1;
8625c6ff4bSstephh
8725c6ff4bSstephh if (nvlist_lookup_string(nvl, FM_FMRI_FMD_NAME, &name) != 0 ||
8825c6ff4bSstephh nvlist_lookup_string(nvl, FM_FMRI_FMD_VERSION, &version) != 0)
8925c6ff4bSstephh return (fmd_fmri_set_errno(EINVAL));
9025c6ff4bSstephh
91*35f59e50SStephen Hanson if (!fmd.d_loaded)
92*35f59e50SStephen Hanson return (FMD_OBJ_STATE_UNKNOWN);
93*35f59e50SStephen Hanson
9425c6ff4bSstephh if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) != NULL) {
9525c6ff4bSstephh rv = mp->mod_vers != NULL &&
9625c6ff4bSstephh strcmp(mp->mod_vers, version) == 0;
9725c6ff4bSstephh fmd_module_rele(mp);
9825c6ff4bSstephh }
9925c6ff4bSstephh
100e58a33b6SStephen Hanson return (rv ? FMD_OBJ_STATE_STILL_PRESENT : FMD_OBJ_STATE_REPLACED);
10125c6ff4bSstephh }
10225c6ff4bSstephh
10325c6ff4bSstephh static int
fmd_scheme_fmd_service_state(nvlist_t * nvl)10425c6ff4bSstephh fmd_scheme_fmd_service_state(nvlist_t *nvl)
10525c6ff4bSstephh {
10625c6ff4bSstephh char *name;
10725c6ff4bSstephh fmd_module_t *mp;
10825c6ff4bSstephh int rv = 1;
10925c6ff4bSstephh
11025c6ff4bSstephh if (nvlist_lookup_string(nvl, FM_FMRI_FMD_NAME, &name) != 0)
11125c6ff4bSstephh return (fmd_fmri_set_errno(EINVAL));
11225c6ff4bSstephh
113*35f59e50SStephen Hanson if (!fmd.d_loaded)
114*35f59e50SStephen Hanson return (FMD_SERVICE_STATE_UNKNOWN);
115*35f59e50SStephen Hanson
11625c6ff4bSstephh if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) != NULL) {
11725c6ff4bSstephh rv = mp->mod_error != 0;
11825c6ff4bSstephh fmd_module_rele(mp);
11925c6ff4bSstephh }
12025c6ff4bSstephh
12125c6ff4bSstephh return (rv ? FMD_SERVICE_STATE_UNUSABLE : FMD_SERVICE_STATE_OK);
12225c6ff4bSstephh }
12325c6ff4bSstephh
12425c6ff4bSstephh static int
fmd_scheme_fmd_unusable(nvlist_t * nvl)1257c478bd9Sstevel@tonic-gate fmd_scheme_fmd_unusable(nvlist_t *nvl)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate char *name;
1287c478bd9Sstevel@tonic-gate fmd_module_t *mp;
1297c478bd9Sstevel@tonic-gate int rv = 1;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(nvl, FM_FMRI_FMD_NAME, &name) != 0)
1327c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL));
1337c478bd9Sstevel@tonic-gate
134*35f59e50SStephen Hanson if (!fmd.d_loaded)
135*35f59e50SStephen Hanson return (0);
136*35f59e50SStephen Hanson
1377c478bd9Sstevel@tonic-gate if ((mp = fmd_modhash_lookup(fmd.d_mod_hash, name)) != NULL) {
1387c478bd9Sstevel@tonic-gate rv = mp->mod_error != 0;
1397c478bd9Sstevel@tonic-gate fmd_module_rele(mp);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate return (rv);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate
145d9638e54Smws /*ARGSUSED*/
146d9638e54Smws static nvlist_t *
fmd_scheme_notranslate(nvlist_t * fmri,nvlist_t * auth)147d9638e54Smws fmd_scheme_notranslate(nvlist_t *fmri, nvlist_t *auth)
148d9638e54Smws {
149d9638e54Smws (void) nvlist_xdup(fmri, &fmri, &fmd.d_nva);
150d9638e54Smws return (fmri);
151d9638e54Smws }
152d9638e54Smws
1537c478bd9Sstevel@tonic-gate static long
fmd_scheme_notsup(void)1547c478bd9Sstevel@tonic-gate fmd_scheme_notsup(void)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_FMRI_NOTSUP));
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate static int
fmd_scheme_nop(void)1607c478bd9Sstevel@tonic-gate fmd_scheme_nop(void)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate return (0);
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate * Default values for the scheme ops. If a scheme function is not defined in
1677c478bd9Sstevel@tonic-gate * the module, then this operation is implemented using the default function.
1687c478bd9Sstevel@tonic-gate */
1697c478bd9Sstevel@tonic-gate static const fmd_scheme_ops_t _fmd_scheme_default_ops = {
1707c478bd9Sstevel@tonic-gate (int (*)())fmd_scheme_nop, /* sop_init */
1717c478bd9Sstevel@tonic-gate (void (*)())fmd_scheme_nop, /* sop_fini */
1727c478bd9Sstevel@tonic-gate (ssize_t (*)())fmd_scheme_notsup, /* sop_nvl2str */
1737c478bd9Sstevel@tonic-gate (int (*)())fmd_scheme_nop, /* sop_expand */
1747c478bd9Sstevel@tonic-gate (int (*)())fmd_scheme_notsup, /* sop_present */
17525c6ff4bSstephh (int (*)())fmd_scheme_notsup, /* sop_replaced */
17625c6ff4bSstephh (int (*)())fmd_scheme_notsup, /* sop_service_state */
1777c478bd9Sstevel@tonic-gate (int (*)())fmd_scheme_notsup, /* sop_unusable */
178d9638e54Smws (int (*)())fmd_scheme_notsup, /* sop_contains */
179d9638e54Smws fmd_scheme_notranslate /* sop_translate */
1807c478bd9Sstevel@tonic-gate };
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate static const fmd_scheme_ops_t _fmd_scheme_builtin_ops = {
1837c478bd9Sstevel@tonic-gate (int (*)())fmd_scheme_nop, /* sop_init */
1847c478bd9Sstevel@tonic-gate (void (*)())fmd_scheme_nop, /* sop_fini */
1857c478bd9Sstevel@tonic-gate fmd_scheme_fmd_nvl2str, /* sop_nvl2str */
1867c478bd9Sstevel@tonic-gate (int (*)())fmd_scheme_nop, /* sop_expand */
1877c478bd9Sstevel@tonic-gate fmd_scheme_fmd_present, /* sop_present */
18825c6ff4bSstephh fmd_scheme_fmd_replaced, /* sop_replaced */
18925c6ff4bSstephh fmd_scheme_fmd_service_state, /* sop_service_state */
1907c478bd9Sstevel@tonic-gate fmd_scheme_fmd_unusable, /* sop_unusable */
191d9638e54Smws (int (*)())fmd_scheme_notsup, /* sop_contains */
192d9638e54Smws fmd_scheme_notranslate /* sop_translate */
1937c478bd9Sstevel@tonic-gate };
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate * Scheme ops descriptions. These names and offsets are used by the function
1977c478bd9Sstevel@tonic-gate * fmd_scheme_rtld_init(), defined below, to load up a fmd_scheme_ops_t.
1987c478bd9Sstevel@tonic-gate */
1997c478bd9Sstevel@tonic-gate static const fmd_scheme_opd_t _fmd_scheme_ops[] = {
2007c478bd9Sstevel@tonic-gate { "fmd_fmri_init", offsetof(fmd_scheme_ops_t, sop_init) },
2017c478bd9Sstevel@tonic-gate { "fmd_fmri_fini", offsetof(fmd_scheme_ops_t, sop_fini) },
2027c478bd9Sstevel@tonic-gate { "fmd_fmri_nvl2str", offsetof(fmd_scheme_ops_t, sop_nvl2str) },
2037c478bd9Sstevel@tonic-gate { "fmd_fmri_expand", offsetof(fmd_scheme_ops_t, sop_expand) },
2047c478bd9Sstevel@tonic-gate { "fmd_fmri_present", offsetof(fmd_scheme_ops_t, sop_present) },
20525c6ff4bSstephh { "fmd_fmri_replaced", offsetof(fmd_scheme_ops_t, sop_replaced) },
20625c6ff4bSstephh { "fmd_fmri_service_state", offsetof(fmd_scheme_ops_t,
20725c6ff4bSstephh sop_service_state) },
2087c478bd9Sstevel@tonic-gate { "fmd_fmri_unusable", offsetof(fmd_scheme_ops_t, sop_unusable) },
2097c478bd9Sstevel@tonic-gate { "fmd_fmri_contains", offsetof(fmd_scheme_ops_t, sop_contains) },
210d9638e54Smws { "fmd_fmri_translate", offsetof(fmd_scheme_ops_t, sop_translate) },
2117c478bd9Sstevel@tonic-gate { NULL, 0 }
2127c478bd9Sstevel@tonic-gate };
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate static fmd_scheme_t *
fmd_scheme_create(const char * name)2157c478bd9Sstevel@tonic-gate fmd_scheme_create(const char *name)
2167c478bd9Sstevel@tonic-gate {
2177c478bd9Sstevel@tonic-gate fmd_scheme_t *sp = fmd_alloc(sizeof (fmd_scheme_t), FMD_SLEEP);
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&sp->sch_lock, NULL);
2207c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&sp->sch_cv, NULL);
2217c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&sp->sch_opslock, NULL);
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate sp->sch_next = NULL;
2247c478bd9Sstevel@tonic-gate sp->sch_name = fmd_strdup(name, FMD_SLEEP);
2257c478bd9Sstevel@tonic-gate sp->sch_dlp = NULL;
2267c478bd9Sstevel@tonic-gate sp->sch_refs = 1;
2277c478bd9Sstevel@tonic-gate sp->sch_loaded = 0;
2287c478bd9Sstevel@tonic-gate sp->sch_ops = _fmd_scheme_default_ops;
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate return (sp);
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate static void
fmd_scheme_destroy(fmd_scheme_t * sp)2347c478bd9Sstevel@tonic-gate fmd_scheme_destroy(fmd_scheme_t *sp)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sp->sch_lock));
2377c478bd9Sstevel@tonic-gate ASSERT(sp->sch_refs == 0);
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate if (sp->sch_dlp != NULL) {
2407c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_FMRI, "dlclose scheme %s", sp->sch_name));
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate if (sp->sch_ops.sop_fini != NULL)
2437c478bd9Sstevel@tonic-gate sp->sch_ops.sop_fini();
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate (void) dlclose(sp->sch_dlp);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate fmd_strfree(sp->sch_name);
2497c478bd9Sstevel@tonic-gate fmd_free(sp, sizeof (fmd_scheme_t));
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate fmd_scheme_hash_t *
fmd_scheme_hash_create(const char * rootdir,const char * dirpath)2537c478bd9Sstevel@tonic-gate fmd_scheme_hash_create(const char *rootdir, const char *dirpath)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate fmd_scheme_hash_t *shp;
2567c478bd9Sstevel@tonic-gate char path[PATH_MAX];
2577c478bd9Sstevel@tonic-gate fmd_scheme_t *sp;
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate shp = fmd_alloc(sizeof (fmd_scheme_hash_t), FMD_SLEEP);
2607c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/%s", rootdir, dirpath);
2617c478bd9Sstevel@tonic-gate shp->sch_dirpath = fmd_strdup(path, FMD_SLEEP);
2627c478bd9Sstevel@tonic-gate (void) pthread_rwlock_init(&shp->sch_rwlock, NULL);
2637c478bd9Sstevel@tonic-gate shp->sch_hashlen = fmd.d_str_buckets;
2647c478bd9Sstevel@tonic-gate shp->sch_hash = fmd_zalloc(sizeof (fmd_scheme_t *) *
2657c478bd9Sstevel@tonic-gate shp->sch_hashlen, FMD_SLEEP);
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate sp = fmd_scheme_create(FM_FMRI_SCHEME_FMD);
2687c478bd9Sstevel@tonic-gate sp->sch_ops = _fmd_scheme_builtin_ops;
2697c478bd9Sstevel@tonic-gate sp->sch_loaded = FMD_B_TRUE;
2707c478bd9Sstevel@tonic-gate shp->sch_hash[fmd_strhash(sp->sch_name) % shp->sch_hashlen] = sp;
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate return (shp);
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate void
fmd_scheme_hash_destroy(fmd_scheme_hash_t * shp)2767c478bd9Sstevel@tonic-gate fmd_scheme_hash_destroy(fmd_scheme_hash_t *shp)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate fmd_scheme_t *sp, *np;
2797c478bd9Sstevel@tonic-gate uint_t i;
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate for (i = 0; i < shp->sch_hashlen; i++) {
2827c478bd9Sstevel@tonic-gate for (sp = shp->sch_hash[i]; sp != NULL; sp = np) {
2837c478bd9Sstevel@tonic-gate np = sp->sch_next;
2847c478bd9Sstevel@tonic-gate sp->sch_next = NULL;
2857c478bd9Sstevel@tonic-gate fmd_scheme_hash_release(shp, sp);
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate fmd_free(shp->sch_hash, sizeof (fmd_scheme_t *) * shp->sch_hashlen);
2907c478bd9Sstevel@tonic-gate fmd_strfree(shp->sch_dirpath);
2917c478bd9Sstevel@tonic-gate fmd_free(shp, sizeof (fmd_scheme_hash_t));
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate void
fmd_scheme_hash_trygc(fmd_scheme_hash_t * shp)2957c478bd9Sstevel@tonic-gate fmd_scheme_hash_trygc(fmd_scheme_hash_t *shp)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate fmd_scheme_t *sp, *np;
2987c478bd9Sstevel@tonic-gate uint_t i;
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate if (shp == NULL || pthread_rwlock_trywrlock(&shp->sch_rwlock) != 0)
3017c478bd9Sstevel@tonic-gate return; /* failed to acquire lock: just skip garbage collect */
3027c478bd9Sstevel@tonic-gate
3037c478bd9Sstevel@tonic-gate for (i = 0; i < shp->sch_hashlen; i++) {
3047c478bd9Sstevel@tonic-gate for (sp = shp->sch_hash[i]; sp != NULL; sp = np) {
3057c478bd9Sstevel@tonic-gate np = sp->sch_next;
3067c478bd9Sstevel@tonic-gate sp->sch_next = NULL;
3077c478bd9Sstevel@tonic-gate fmd_scheme_hash_release(shp, sp);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate bzero(shp->sch_hash, sizeof (fmd_scheme_t *) * shp->sch_hashlen);
3127c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&shp->sch_rwlock);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate static int
fmd_scheme_rtld_init(fmd_scheme_t * sp)3167c478bd9Sstevel@tonic-gate fmd_scheme_rtld_init(fmd_scheme_t *sp)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate const fmd_scheme_opd_t *opd;
3197c478bd9Sstevel@tonic-gate void *p;
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate for (opd = _fmd_scheme_ops; opd->opd_name != NULL; opd++) {
3227c478bd9Sstevel@tonic-gate if ((p = dlsym(sp->sch_dlp, opd->opd_name)) != NULL)
3237c478bd9Sstevel@tonic-gate *(void **)((uintptr_t)&sp->sch_ops + opd->opd_off) = p;
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate return (0);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate fmd_scheme_t *
fmd_scheme_hash_xlookup(fmd_scheme_hash_t * shp,const char * name,uint_t h)3307c478bd9Sstevel@tonic-gate fmd_scheme_hash_xlookup(fmd_scheme_hash_t *shp, const char *name, uint_t h)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate fmd_scheme_t *sp;
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&shp->sch_rwlock));
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate for (sp = shp->sch_hash[h]; sp != NULL; sp = sp->sch_next) {
3377c478bd9Sstevel@tonic-gate if (strcmp(sp->sch_name, name) == 0)
3387c478bd9Sstevel@tonic-gate break;
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate return (sp);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate * Lookup a scheme module by name and return with a reference placed on it. We
3467c478bd9Sstevel@tonic-gate * use the scheme hash to cache "negative" entries (e.g. missing modules) as
3477c478bd9Sstevel@tonic-gate * well so this function always returns successfully with a non-NULL scheme.
3487c478bd9Sstevel@tonic-gate * The caller is responsible for applying fmd_scheme_hash_release() afterward.
3497c478bd9Sstevel@tonic-gate */
3507c478bd9Sstevel@tonic-gate fmd_scheme_t *
fmd_scheme_hash_lookup(fmd_scheme_hash_t * shp,const char * name)3517c478bd9Sstevel@tonic-gate fmd_scheme_hash_lookup(fmd_scheme_hash_t *shp, const char *name)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate fmd_scheme_t *sp, *nsp = NULL;
3547c478bd9Sstevel@tonic-gate uint_t h;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate * Grab the hash lock as reader and look for the appropriate scheme.
3587c478bd9Sstevel@tonic-gate * If the scheme isn't yet loaded, allocate a new scheme and grab the
3597c478bd9Sstevel@tonic-gate * hash lock as writer to insert it (after checking again for it).
3607c478bd9Sstevel@tonic-gate */
3617c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&shp->sch_rwlock);
3627c478bd9Sstevel@tonic-gate h = fmd_strhash(name) % shp->sch_hashlen;
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate if ((sp = fmd_scheme_hash_xlookup(shp, name, h)) == NULL) {
3657c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&shp->sch_rwlock);
3667c478bd9Sstevel@tonic-gate nsp = fmd_scheme_create(name);
3677c478bd9Sstevel@tonic-gate (void) pthread_rwlock_wrlock(&shp->sch_rwlock);
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate if ((sp = fmd_scheme_hash_xlookup(shp, name, h)) == NULL) {
3707c478bd9Sstevel@tonic-gate nsp->sch_next = shp->sch_hash[h];
3717c478bd9Sstevel@tonic-gate shp->sch_hash[h] = sp = nsp;
3727c478bd9Sstevel@tonic-gate } else {
3737c478bd9Sstevel@tonic-gate fmd_scheme_hash_release(shp, nsp);
3747c478bd9Sstevel@tonic-gate nsp = NULL;
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate * Grab the scheme lock so it can't disappear and then drop the hash
3807c478bd9Sstevel@tonic-gate * lock so that other lookups in the scheme hash can proceed.
3817c478bd9Sstevel@tonic-gate */
3827c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&sp->sch_lock);
3837c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&shp->sch_rwlock);
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate * If we created the scheme, compute its path and try to load it. If
3877c478bd9Sstevel@tonic-gate * we found an existing scheme, wait until its loaded bit is set. Once
3887c478bd9Sstevel@tonic-gate * we're done with either operation, increment sch_refs and return.
3897c478bd9Sstevel@tonic-gate */
3907c478bd9Sstevel@tonic-gate if (nsp != NULL) {
3917c478bd9Sstevel@tonic-gate char path[PATH_MAX];
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path),
3947c478bd9Sstevel@tonic-gate "%s/%s.so", shp->sch_dirpath, sp->sch_name);
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_FMRI, "dlopen scheme %s", sp->sch_name));
3977c478bd9Sstevel@tonic-gate sp->sch_dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW);
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate if (sp->sch_dlp == NULL) {
4007c478bd9Sstevel@tonic-gate fmd_error(EFMD_FMRI_SCHEME,
4017c478bd9Sstevel@tonic-gate "failed to load fmri scheme %s: %s\n", path,
4027c478bd9Sstevel@tonic-gate dlerror());
4037c478bd9Sstevel@tonic-gate } else if (fmd_scheme_rtld_init(sp) != 0 ||
4047c478bd9Sstevel@tonic-gate sp->sch_ops.sop_init() != 0) {
4057c478bd9Sstevel@tonic-gate fmd_error(EFMD_FMRI_SCHEME,
4067c478bd9Sstevel@tonic-gate "failed to initialize fmri scheme %s", path);
4077c478bd9Sstevel@tonic-gate (void) dlclose(sp->sch_dlp);
4087c478bd9Sstevel@tonic-gate sp->sch_dlp = NULL;
4097c478bd9Sstevel@tonic-gate sp->sch_ops = _fmd_scheme_default_ops;
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate sp->sch_loaded = FMD_B_TRUE; /* set regardless of success */
4137c478bd9Sstevel@tonic-gate sp->sch_refs++;
4147c478bd9Sstevel@tonic-gate ASSERT(sp->sch_refs != 0);
415d9638e54Smws
4167c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&sp->sch_cv);
417d9638e54Smws (void) pthread_mutex_unlock(&sp->sch_lock);
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate } else {
4207c478bd9Sstevel@tonic-gate while (!sp->sch_loaded)
4217c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&sp->sch_cv, &sp->sch_lock);
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate sp->sch_refs++;
4247c478bd9Sstevel@tonic-gate ASSERT(sp->sch_refs != 0);
4257c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&sp->sch_lock);
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate return (sp);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate /*
4327c478bd9Sstevel@tonic-gate * Release the hold on a scheme obtained using fmd_scheme_hash_lookup().
4337c478bd9Sstevel@tonic-gate * We take 'shp' for symmetry and in case we need to use it in future work.
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4367c478bd9Sstevel@tonic-gate void
fmd_scheme_hash_release(fmd_scheme_hash_t * shp,fmd_scheme_t * sp)4377c478bd9Sstevel@tonic-gate fmd_scheme_hash_release(fmd_scheme_hash_t *shp, fmd_scheme_t *sp)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&sp->sch_lock);
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate ASSERT(sp->sch_refs != 0);
4427c478bd9Sstevel@tonic-gate if (--sp->sch_refs == 0)
4437c478bd9Sstevel@tonic-gate fmd_scheme_destroy(sp);
4447c478bd9Sstevel@tonic-gate else
4457c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&sp->sch_lock);
4467c478bd9Sstevel@tonic-gate }
447