49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * CDDL HEADER START
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * The contents of this file are subject to the terms of the
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Common Development and Distribution License (the "License").
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * You may not use this file except in compliance with the License.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * See the License for the specific language governing permissions
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * and limitations under the License.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * When distributing Covered Code, include this CDDL HEADER in each
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * If applicable, add the following below this CDDL HEADER, with the
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * fields enclosed by brackets "[]" replaced with your own identifying
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * information: Portions Copyright [yyyy] [name of copyright owner]
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * CDDL HEADER END
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * FMA event subscription interfaces - subscribe to FMA protocol
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * from outside the fault manager.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbytypedef struct {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby#define HDL2IHDL(hdl) ((fmev_shdl_impl_t *)(hdl))
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby#define FMEV_SHDL_VALID(ihdl) ((ihdl)->sh_cmn.hc_magic == _FMEV_SHMAGIC)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby fmev_api_enter(&HDL2IHDL(hdl)->sh_cmn, LIBFMEVENT_VERSION_##v)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * For each subscription on a handle we add a node to an avl tree
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * to track subscriptions.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby#define FMEV_SID_SZ (16 + 1) /* Matches MAX_SUBID_LEN */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) pthread_mutex_init(&ihdl->sh_srlz_lock, NULL);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_shdlctl_thrattr(fmev_shdl_t hdl, pthread_attr_t *attr)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_shdlctl_sigmask(fmev_shdl_t hdl, sigset_t *set)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_shdlctl_thrsetup(fmev_shdl_t hdl, door_xcreate_thrsetup_func_t *func,
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby sysevent_subattr_thrsetup(ihdl->sh_attr, func, cookie);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_shdlctl_thrcreate(fmev_shdl_t hdl, door_xcreate_server_func_t *func,
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby sysevent_subattr_thrcreate(ihdl->sh_attr, func, cookie);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Our door service function. We return 0 regardless so that the kernel
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * does not keep either retrying (EAGAIN) or bleat to cmn_err.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((ev = fmev_sysev2fmev(IHDL2HDL(ihdl), sep, &class, &nvl)) == NULL) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) pthread_mutex_lock(&ihdl->sh_srlz_lock);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) pthread_mutex_unlock(&ihdl->sh_srlz_lock);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby fmev_rele(ev); /* release hold obtained in fmev_sysev2fmev */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_shdl_subscribe(fmev_shdl_t hdl, const char *pat, fmev_cbfunc_t func,
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Empty class patterns are illegal, as is the sysevent magic for
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * all classes. Also validate class length.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (*pat == '\0' || strncmp(pat, EC_ALL, sizeof (EC_ALL)) == 0 ||
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby strncmp(pat, EC_SUB_ALL, sizeof (EC_SUB_ALL)) == 0 ||
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby strnlen(pat, FMEV_MAX_CLASS) == FMEV_MAX_CLASS)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((sip = fmev_shdl_zalloc(hdl, sizeof (*sip))) == NULL)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) strncpy(sip->si_pat, pat, sizeof (sip->si_pat));
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby uu_avl_node_init(sip, &sip->si_node, ihdl->sh_pool);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (uu_avl_find(ihdl->sh_avl, sip, NULL, &idx) != NULL) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Generate a subscriber id for GPEC that is unique to this
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * subscription. There is no provision for persistent
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * subscribers. The subscriber id must be unique within
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * this zone.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby nsid = (uint64_t)getpid() << 32 | atomic_inc_32_nv(&fmev_subid);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) snprintf(sip->si_sid, sizeof (sip->si_sid), "%llx", nsid);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((serr = sysevent_evc_xsubscribe(ihdl->sh_binding, sip->si_sid,
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby sip->si_pat, fmev_proxy_cb, sip, 0, ihdl->sh_attr)) != 0) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_subinfo_fini(fmev_shdl_impl_t *ihdl, struct fmev_subinfo *sip,
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby err = sysevent_evc_unsubscribe(ihdl->sh_binding, sip->si_sid);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby uu_avl_node_fini(sip, &sip->si_node, ihdl->sh_pool);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby fmev_shdl_free(IHDL2HDL(ihdl), sip, sizeof (*sip));
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_shdl_unsubscribe(fmev_shdl_t hdl, const char *pat)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (*pat == '\0' || strncmp(pat, EVCH_ALLSUB, sizeof (EC_ALL)) == 0 ||
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby strnlen(pat, FMEV_MAX_CLASS) == FMEV_MAX_CLASS)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) strncpy(si.si_pat, pat, sizeof (si.si_pat));
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((sip = uu_avl_find(ihdl->sh_avl, &si, NULL, NULL)) != NULL) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((err = fmev_subinfo_fini(ihdl, sip, B_TRUE)) == 0) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Return an API error if the unsubscribe was
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * attempted from within a door callback invocation;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * other errors should not happen.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby rv = (err == EDEADLK) ? FMEVERR_API : FMEVERR_INTERNAL;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_shdl_free(fmev_shdl_t hdl, void *buf, size_t sz)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if ((dst = ihdl->sh_cmn.hc_alloc(srclen + 1)) == NULL) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_keycmp(const void *l, const void *r, void *arg)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby struct fmev_subinfo *left = (struct fmev_subinfo *)l;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby struct fmev_subinfo *right = (struct fmev_subinfo *)r;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby return (strncmp(left->si_pat, right->si_pat, FMEV_MAX_CLASS));
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_shdl_init(uint32_t caller_version, void *(*hdlalloc)(size_t),
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby void *(*hdlzalloc)(size_t), void (*hdlfree)(void *, size_t))
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby hc.hc_alloc = hdlalloc ? hdlalloc : dflt_alloc;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby hc.hc_zalloc = hdlzalloc ? hdlzalloc : dflt_zalloc;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (!((hdlalloc == NULL && hdlzalloc == NULL && hdlfree == NULL) ||
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (hdlalloc != NULL && hdlzalloc != NULL && hdlfree != NULL))) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((ihdl->sh_attr = sysevent_subattr_alloc()) == NULL) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) pthread_mutex_init(&ihdl->sh_lock, NULL);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * For simulation purposes we allow an environment variable
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * to provide a different channel name.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((chan_name = getenv("FMD_SNOOP_CHANNEL")) == NULL)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Try to bind to the event channel. If it's not already present,
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * attempt to create the channel so that we can startup before
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * the event producer (who will also apply choices such as
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * channel depth when they bind to the channel).
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (sysevent_evc_bind(chan_name, &ihdl->sh_binding,
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((ihdl->sh_pool = uu_avl_pool_create("subinfo_pool",
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby sizeof (struct fmev_subinfo),
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby offsetof(struct fmev_subinfo, si_node), fmev_keycmp,
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((ihdl->sh_avl = uu_avl_create(ihdl->sh_pool, NULL,
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbyfmev_shdl_getauthority(fmev_shdl_t hdl, nvlist_t **nvlp)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (sysevent_evc_getpropnvl(ihdl->sh_binding, &propnvl) != 0) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby rc = FMEVERR_BUSY; /* Other end has not bound */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (nvlist_lookup_nvlist(propnvl, "fmdauth", &auth) == 0) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby rc = (nvlist_dup(auth, nvlp, 0) == 0) ? FMEV_SUCCESS :
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbyfmev_shdl_nvl2str(fmev_shdl_t hdl, nvlist_t *nvl)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby g_topohdl = topo_open(TOPO_VERSION, NULL, &topoerr);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (topo_fmri_nvl2str(g_topohdl, nvl, &fmri, &topoerr) == 0) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (fmricp); /* fmev_errno set if strdup failed */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Verify that we are not in callback context - return an API
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * error if we are.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (sysevent_evc_unsubscribe(ihdl->sh_binding, "invalidsid") ==
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby while ((sip = uu_avl_teardown(ihdl->sh_avl, &cookie)) != NULL)