xref: /onnv-gate/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c (revision 12967:ab9ae749152f)
111102SGavin.Maltby@Sun.COM /*
211102SGavin.Maltby@Sun.COM  * CDDL HEADER START
311102SGavin.Maltby@Sun.COM  *
411102SGavin.Maltby@Sun.COM  * The contents of this file are subject to the terms of the
511102SGavin.Maltby@Sun.COM  * Common Development and Distribution License (the "License").
611102SGavin.Maltby@Sun.COM  * You may not use this file except in compliance with the License.
711102SGavin.Maltby@Sun.COM  *
811102SGavin.Maltby@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911102SGavin.Maltby@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011102SGavin.Maltby@Sun.COM  * See the License for the specific language governing permissions
1111102SGavin.Maltby@Sun.COM  * and limitations under the License.
1211102SGavin.Maltby@Sun.COM  *
1311102SGavin.Maltby@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411102SGavin.Maltby@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511102SGavin.Maltby@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611102SGavin.Maltby@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711102SGavin.Maltby@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811102SGavin.Maltby@Sun.COM  *
1911102SGavin.Maltby@Sun.COM  * CDDL HEADER END
2011102SGavin.Maltby@Sun.COM  */
2111102SGavin.Maltby@Sun.COM 
2211102SGavin.Maltby@Sun.COM /*
23*12967Sgavin.maltby@oracle.com  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2411102SGavin.Maltby@Sun.COM  */
2511102SGavin.Maltby@Sun.COM 
2611102SGavin.Maltby@Sun.COM /*
2711102SGavin.Maltby@Sun.COM  * FMA event subscription interfaces - subscribe to FMA protocol
2811102SGavin.Maltby@Sun.COM  * from outside the fault manager.
2911102SGavin.Maltby@Sun.COM  */
3011102SGavin.Maltby@Sun.COM 
3111102SGavin.Maltby@Sun.COM #include <sys/types.h>
3211102SGavin.Maltby@Sun.COM #include <atomic.h>
3311102SGavin.Maltby@Sun.COM #include <libsysevent.h>
3411102SGavin.Maltby@Sun.COM #include <libuutil.h>
3511102SGavin.Maltby@Sun.COM #include <pthread.h>
3611102SGavin.Maltby@Sun.COM #include <stdarg.h>
3711102SGavin.Maltby@Sun.COM #include <stdlib.h>
3811102SGavin.Maltby@Sun.COM #include <string.h>
3911102SGavin.Maltby@Sun.COM #include <strings.h>
4011102SGavin.Maltby@Sun.COM #include <unistd.h>
41*12967Sgavin.maltby@oracle.com #include <fm/libtopo.h>
4211102SGavin.Maltby@Sun.COM 
4311102SGavin.Maltby@Sun.COM #include <fm/libfmevent.h>
4411102SGavin.Maltby@Sun.COM 
4511102SGavin.Maltby@Sun.COM #include "fmev_impl.h"
46*12967Sgavin.maltby@oracle.com 
47*12967Sgavin.maltby@oracle.com static topo_hdl_t *g_topohdl;
4811102SGavin.Maltby@Sun.COM 
4911102SGavin.Maltby@Sun.COM typedef struct {
5011102SGavin.Maltby@Sun.COM 	struct fmev_hdl_cmn sh_cmn;
5111102SGavin.Maltby@Sun.COM 	evchan_t *sh_binding;
5211102SGavin.Maltby@Sun.COM 	uu_avl_pool_t *sh_pool;
5311102SGavin.Maltby@Sun.COM 	uu_avl_t *sh_avl;
5411102SGavin.Maltby@Sun.COM 	uint32_t sh_subcnt;
5511102SGavin.Maltby@Sun.COM 	uint32_t sh_flags;
5611102SGavin.Maltby@Sun.COM 	sysevent_subattr_t *sh_attr;
5711102SGavin.Maltby@Sun.COM 	pthread_mutex_t sh_lock;
5811102SGavin.Maltby@Sun.COM 	pthread_mutex_t sh_srlz_lock;
5911102SGavin.Maltby@Sun.COM } fmev_shdl_impl_t;
6011102SGavin.Maltby@Sun.COM 
6111102SGavin.Maltby@Sun.COM #define	HDL2IHDL(hdl)	((fmev_shdl_impl_t *)(hdl))
6211102SGavin.Maltby@Sun.COM #define	IHDL2HDL(ihdl)	((fmev_shdl_t)(ihdl))
6311102SGavin.Maltby@Sun.COM 
6411102SGavin.Maltby@Sun.COM #define	_FMEV_SHMAGIC	0x5368446c	/* ShDl */
6511102SGavin.Maltby@Sun.COM #define	FMEV_SHDL_VALID(ihdl)	((ihdl)->sh_cmn.hc_magic == _FMEV_SHMAGIC)
6611102SGavin.Maltby@Sun.COM 
6711102SGavin.Maltby@Sun.COM #define	SHDL_FL_SERIALIZE	0x1
6811102SGavin.Maltby@Sun.COM 
69*12967Sgavin.maltby@oracle.com #define	FMEV_API_ENTER(hdl, v) \
70*12967Sgavin.maltby@oracle.com 	fmev_api_enter(&HDL2IHDL(hdl)->sh_cmn, LIBFMEVENT_VERSION_##v)
7111102SGavin.Maltby@Sun.COM 
7211102SGavin.Maltby@Sun.COM /*
7311102SGavin.Maltby@Sun.COM  * For each subscription on a handle we add a node to an avl tree
7411102SGavin.Maltby@Sun.COM  * to track subscriptions.
7511102SGavin.Maltby@Sun.COM  */
7611102SGavin.Maltby@Sun.COM 
7711102SGavin.Maltby@Sun.COM #define	FMEV_SID_SZ	(16 + 1)	/* Matches MAX_SUBID_LEN */
7811102SGavin.Maltby@Sun.COM 
7911102SGavin.Maltby@Sun.COM struct fmev_subinfo {
8011102SGavin.Maltby@Sun.COM 	uu_avl_node_t si_node;
8111102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *si_ihdl;
8211102SGavin.Maltby@Sun.COM 	char si_pat[FMEV_MAX_CLASS];
8311102SGavin.Maltby@Sun.COM 	char si_sid[FMEV_SID_SZ];
8411102SGavin.Maltby@Sun.COM 	fmev_cbfunc_t *si_cb;
8511102SGavin.Maltby@Sun.COM 	void *si_cbarg;
8611102SGavin.Maltby@Sun.COM };
8711102SGavin.Maltby@Sun.COM 
8811102SGavin.Maltby@Sun.COM struct fmev_hdl_cmn *
fmev_shdl_cmn(fmev_shdl_t hdl)8911102SGavin.Maltby@Sun.COM fmev_shdl_cmn(fmev_shdl_t hdl)
9011102SGavin.Maltby@Sun.COM {
9111102SGavin.Maltby@Sun.COM 	return (&HDL2IHDL(hdl)->sh_cmn);
9211102SGavin.Maltby@Sun.COM }
9311102SGavin.Maltby@Sun.COM 
9411102SGavin.Maltby@Sun.COM static int
shdlctl_start(fmev_shdl_impl_t * ihdl)9511102SGavin.Maltby@Sun.COM shdlctl_start(fmev_shdl_impl_t *ihdl)
9611102SGavin.Maltby@Sun.COM {
9711102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_lock(&ihdl->sh_lock);
9811102SGavin.Maltby@Sun.COM 
9911102SGavin.Maltby@Sun.COM 	if (ihdl->sh_subcnt == 0) {
10011102SGavin.Maltby@Sun.COM 		return (1);	/* lock still held */
10111102SGavin.Maltby@Sun.COM 	} else {
10211102SGavin.Maltby@Sun.COM 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
10311102SGavin.Maltby@Sun.COM 		return (0);
10411102SGavin.Maltby@Sun.COM 	}
10511102SGavin.Maltby@Sun.COM }
10611102SGavin.Maltby@Sun.COM 
10711102SGavin.Maltby@Sun.COM static void
shdlctl_end(fmev_shdl_impl_t * ihdl)10811102SGavin.Maltby@Sun.COM shdlctl_end(fmev_shdl_impl_t *ihdl)
10911102SGavin.Maltby@Sun.COM {
11011102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
11111102SGavin.Maltby@Sun.COM }
11211102SGavin.Maltby@Sun.COM 
11311102SGavin.Maltby@Sun.COM fmev_err_t
fmev_shdlctl_serialize(fmev_shdl_t hdl)11411102SGavin.Maltby@Sun.COM fmev_shdlctl_serialize(fmev_shdl_t hdl)
11511102SGavin.Maltby@Sun.COM {
11611102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
11711102SGavin.Maltby@Sun.COM 
118*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
11911102SGavin.Maltby@Sun.COM 		return (fmev_errno);
12011102SGavin.Maltby@Sun.COM 
12111102SGavin.Maltby@Sun.COM 	if (!shdlctl_start(ihdl))
12211102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_BUSY));
12311102SGavin.Maltby@Sun.COM 
12411102SGavin.Maltby@Sun.COM 	if (!(ihdl->sh_flags & SHDL_FL_SERIALIZE)) {
12511102SGavin.Maltby@Sun.COM 		(void) pthread_mutex_init(&ihdl->sh_srlz_lock, NULL);
12611102SGavin.Maltby@Sun.COM 		ihdl->sh_flags |= SHDL_FL_SERIALIZE;
12711102SGavin.Maltby@Sun.COM 	}
12811102SGavin.Maltby@Sun.COM 
12911102SGavin.Maltby@Sun.COM 	shdlctl_end(ihdl);
13011102SGavin.Maltby@Sun.COM 	return (fmev_seterr(FMEV_SUCCESS));
13111102SGavin.Maltby@Sun.COM }
13211102SGavin.Maltby@Sun.COM 
13311102SGavin.Maltby@Sun.COM fmev_err_t
fmev_shdlctl_thrattr(fmev_shdl_t hdl,pthread_attr_t * attr)13411102SGavin.Maltby@Sun.COM fmev_shdlctl_thrattr(fmev_shdl_t hdl, pthread_attr_t *attr)
13511102SGavin.Maltby@Sun.COM {
13611102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
13711102SGavin.Maltby@Sun.COM 
138*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
13911102SGavin.Maltby@Sun.COM 		return (fmev_errno);
14011102SGavin.Maltby@Sun.COM 
14111102SGavin.Maltby@Sun.COM 	if (!shdlctl_start(ihdl))
14211102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_BUSY));
14311102SGavin.Maltby@Sun.COM 
14411102SGavin.Maltby@Sun.COM 	sysevent_subattr_thrattr(ihdl->sh_attr, attr);
14511102SGavin.Maltby@Sun.COM 
14611102SGavin.Maltby@Sun.COM 	shdlctl_end(ihdl);
14711102SGavin.Maltby@Sun.COM 	return (fmev_seterr(FMEV_SUCCESS));
14811102SGavin.Maltby@Sun.COM }
14911102SGavin.Maltby@Sun.COM 
15011102SGavin.Maltby@Sun.COM fmev_err_t
fmev_shdlctl_sigmask(fmev_shdl_t hdl,sigset_t * set)15111102SGavin.Maltby@Sun.COM fmev_shdlctl_sigmask(fmev_shdl_t hdl, sigset_t *set)
15211102SGavin.Maltby@Sun.COM {
15311102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
15411102SGavin.Maltby@Sun.COM 
155*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
15611102SGavin.Maltby@Sun.COM 		return (fmev_errno);
15711102SGavin.Maltby@Sun.COM 
15811102SGavin.Maltby@Sun.COM 	if (!shdlctl_start(ihdl))
15911102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_BUSY));
16011102SGavin.Maltby@Sun.COM 
16111102SGavin.Maltby@Sun.COM 	sysevent_subattr_sigmask(ihdl->sh_attr, set);
16211102SGavin.Maltby@Sun.COM 
16311102SGavin.Maltby@Sun.COM 	shdlctl_end(ihdl);
16411102SGavin.Maltby@Sun.COM 	return (fmev_seterr(FMEV_SUCCESS));
16511102SGavin.Maltby@Sun.COM }
16611102SGavin.Maltby@Sun.COM 
16711102SGavin.Maltby@Sun.COM fmev_err_t
fmev_shdlctl_thrsetup(fmev_shdl_t hdl,door_xcreate_thrsetup_func_t * func,void * cookie)16811102SGavin.Maltby@Sun.COM fmev_shdlctl_thrsetup(fmev_shdl_t hdl, door_xcreate_thrsetup_func_t *func,
16911102SGavin.Maltby@Sun.COM     void *cookie)
17011102SGavin.Maltby@Sun.COM {
17111102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
17211102SGavin.Maltby@Sun.COM 
173*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
17411102SGavin.Maltby@Sun.COM 		return (fmev_errno);
17511102SGavin.Maltby@Sun.COM 
17611102SGavin.Maltby@Sun.COM 	if (!shdlctl_start(ihdl))
17711102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_BUSY));
17811102SGavin.Maltby@Sun.COM 
17911102SGavin.Maltby@Sun.COM 	sysevent_subattr_thrsetup(ihdl->sh_attr, func, cookie);
18011102SGavin.Maltby@Sun.COM 
18111102SGavin.Maltby@Sun.COM 	shdlctl_end(ihdl);
18211102SGavin.Maltby@Sun.COM 	return (fmev_seterr(FMEV_SUCCESS));
18311102SGavin.Maltby@Sun.COM }
18411102SGavin.Maltby@Sun.COM 
18511102SGavin.Maltby@Sun.COM fmev_err_t
fmev_shdlctl_thrcreate(fmev_shdl_t hdl,door_xcreate_server_func_t * func,void * cookie)18611102SGavin.Maltby@Sun.COM fmev_shdlctl_thrcreate(fmev_shdl_t hdl, door_xcreate_server_func_t *func,
18711102SGavin.Maltby@Sun.COM     void *cookie)
18811102SGavin.Maltby@Sun.COM {
18911102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
19011102SGavin.Maltby@Sun.COM 
191*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
19211102SGavin.Maltby@Sun.COM 		return (fmev_errno);
19311102SGavin.Maltby@Sun.COM 
19411102SGavin.Maltby@Sun.COM 	if (!shdlctl_start(ihdl))
19511102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_BUSY));
19611102SGavin.Maltby@Sun.COM 
19711102SGavin.Maltby@Sun.COM 	sysevent_subattr_thrcreate(ihdl->sh_attr, func, cookie);
19811102SGavin.Maltby@Sun.COM 
19911102SGavin.Maltby@Sun.COM 	shdlctl_end(ihdl);
20011102SGavin.Maltby@Sun.COM 	return (fmev_seterr(FMEV_SUCCESS));
20111102SGavin.Maltby@Sun.COM }
20211102SGavin.Maltby@Sun.COM 
20311102SGavin.Maltby@Sun.COM /*
20411102SGavin.Maltby@Sun.COM  * Our door service function.  We return 0 regardless so that the kernel
20511102SGavin.Maltby@Sun.COM  * does not keep either retrying (EAGAIN) or bleat to cmn_err.
20611102SGavin.Maltby@Sun.COM  */
20711102SGavin.Maltby@Sun.COM 
20811102SGavin.Maltby@Sun.COM uint64_t fmev_proxy_cb_inval;
20911102SGavin.Maltby@Sun.COM uint64_t fmev_proxy_cb_enomem;
21011102SGavin.Maltby@Sun.COM 
21111102SGavin.Maltby@Sun.COM int
fmev_proxy_cb(sysevent_t * sep,void * arg)21211102SGavin.Maltby@Sun.COM fmev_proxy_cb(sysevent_t *sep, void *arg)
21311102SGavin.Maltby@Sun.COM {
21411102SGavin.Maltby@Sun.COM 	struct fmev_subinfo *sip = arg;
21511102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = sip->si_ihdl;
21611102SGavin.Maltby@Sun.COM 	nvlist_t *nvl;
21711102SGavin.Maltby@Sun.COM 	char *class;
21811102SGavin.Maltby@Sun.COM 	fmev_t ev;
21911102SGavin.Maltby@Sun.COM 
22011102SGavin.Maltby@Sun.COM 	if (sip == NULL || sip->si_cb == NULL) {
22111102SGavin.Maltby@Sun.COM 		fmev_proxy_cb_inval++;
22211102SGavin.Maltby@Sun.COM 		return (0);
22311102SGavin.Maltby@Sun.COM 	}
22411102SGavin.Maltby@Sun.COM 
22511102SGavin.Maltby@Sun.COM 	if ((ev = fmev_sysev2fmev(IHDL2HDL(ihdl), sep, &class, &nvl)) == NULL) {
22611102SGavin.Maltby@Sun.COM 		fmev_proxy_cb_enomem++;
22711102SGavin.Maltby@Sun.COM 		return (0);
22811102SGavin.Maltby@Sun.COM 	}
22911102SGavin.Maltby@Sun.COM 
23011102SGavin.Maltby@Sun.COM 	if (ihdl->sh_flags & SHDL_FL_SERIALIZE)
23111102SGavin.Maltby@Sun.COM 		(void) pthread_mutex_lock(&ihdl->sh_srlz_lock);
23211102SGavin.Maltby@Sun.COM 
23311102SGavin.Maltby@Sun.COM 	sip->si_cb(ev, class, nvl, sip->si_cbarg);
23411102SGavin.Maltby@Sun.COM 
23511102SGavin.Maltby@Sun.COM 	if (ihdl->sh_flags & SHDL_FL_SERIALIZE)
23611102SGavin.Maltby@Sun.COM 		(void) pthread_mutex_unlock(&ihdl->sh_srlz_lock);
23711102SGavin.Maltby@Sun.COM 
23811102SGavin.Maltby@Sun.COM 	fmev_rele(ev);	/* release hold obtained in fmev_sysev2fmev */
23911102SGavin.Maltby@Sun.COM 
24011102SGavin.Maltby@Sun.COM 	return (0);
24111102SGavin.Maltby@Sun.COM }
24211102SGavin.Maltby@Sun.COM 
24311102SGavin.Maltby@Sun.COM static volatile uint32_t fmev_subid;
24411102SGavin.Maltby@Sun.COM 
24511102SGavin.Maltby@Sun.COM fmev_err_t
fmev_shdl_subscribe(fmev_shdl_t hdl,const char * pat,fmev_cbfunc_t func,void * funcarg)24611102SGavin.Maltby@Sun.COM fmev_shdl_subscribe(fmev_shdl_t hdl, const char *pat, fmev_cbfunc_t func,
24711102SGavin.Maltby@Sun.COM     void *funcarg)
24811102SGavin.Maltby@Sun.COM {
24911102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
25011102SGavin.Maltby@Sun.COM 	struct fmev_subinfo *sip;
25111102SGavin.Maltby@Sun.COM 	uu_avl_index_t idx;
25211102SGavin.Maltby@Sun.COM 	uint64_t nsid;
25311102SGavin.Maltby@Sun.COM 	int serr;
25411102SGavin.Maltby@Sun.COM 
255*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
25611102SGavin.Maltby@Sun.COM 		return (fmev_errno);
25711102SGavin.Maltby@Sun.COM 
25811102SGavin.Maltby@Sun.COM 	if (pat == NULL || func == NULL)
25911102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_API));
26011102SGavin.Maltby@Sun.COM 
26111102SGavin.Maltby@Sun.COM 	/*
26211102SGavin.Maltby@Sun.COM 	 * Empty class patterns are illegal, as is the sysevent magic for
26311102SGavin.Maltby@Sun.COM 	 * all classes.  Also validate class length.
26411102SGavin.Maltby@Sun.COM 	 */
26511102SGavin.Maltby@Sun.COM 	if (*pat == '\0' || strncmp(pat, EC_ALL, sizeof (EC_ALL)) == 0 ||
26611102SGavin.Maltby@Sun.COM 	    strncmp(pat, EC_SUB_ALL, sizeof (EC_SUB_ALL)) == 0 ||
26711102SGavin.Maltby@Sun.COM 	    strnlen(pat, FMEV_MAX_CLASS) == FMEV_MAX_CLASS)
26811102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_BADCLASS));
26911102SGavin.Maltby@Sun.COM 
27011102SGavin.Maltby@Sun.COM 	if ((sip = fmev_shdl_zalloc(hdl, sizeof (*sip))) == NULL)
27111102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_ALLOC));
27211102SGavin.Maltby@Sun.COM 
27311102SGavin.Maltby@Sun.COM 	(void) strncpy(sip->si_pat, pat, sizeof (sip->si_pat));
27411102SGavin.Maltby@Sun.COM 
27511102SGavin.Maltby@Sun.COM 	uu_avl_node_init(sip, &sip->si_node, ihdl->sh_pool);
27611102SGavin.Maltby@Sun.COM 
27711102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_lock(&ihdl->sh_lock);
27811102SGavin.Maltby@Sun.COM 
27911102SGavin.Maltby@Sun.COM 	if (uu_avl_find(ihdl->sh_avl, sip, NULL, &idx) != NULL) {
28011102SGavin.Maltby@Sun.COM 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
28111102SGavin.Maltby@Sun.COM 		fmev_shdl_free(hdl, sip, sizeof (*sip));
28211102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_DUPLICATE));
28311102SGavin.Maltby@Sun.COM 	}
28411102SGavin.Maltby@Sun.COM 
28511102SGavin.Maltby@Sun.COM 	/*
28611102SGavin.Maltby@Sun.COM 	 * Generate a subscriber id for GPEC that is unique to this
28711102SGavin.Maltby@Sun.COM 	 * subscription.  There is no provision for persistent
28811102SGavin.Maltby@Sun.COM 	 * subscribers.  The subscriber id must be unique within
28911102SGavin.Maltby@Sun.COM 	 * this zone.
29011102SGavin.Maltby@Sun.COM 	 */
29111102SGavin.Maltby@Sun.COM 	nsid = (uint64_t)getpid() << 32 | atomic_inc_32_nv(&fmev_subid);
29211102SGavin.Maltby@Sun.COM 	(void) snprintf(sip->si_sid, sizeof (sip->si_sid), "%llx", nsid);
29311102SGavin.Maltby@Sun.COM 
29411102SGavin.Maltby@Sun.COM 	sip->si_ihdl = ihdl;
29511102SGavin.Maltby@Sun.COM 	sip->si_cb = func;
29611102SGavin.Maltby@Sun.COM 	sip->si_cbarg = funcarg;
29711102SGavin.Maltby@Sun.COM 
29811102SGavin.Maltby@Sun.COM 	if ((serr = sysevent_evc_xsubscribe(ihdl->sh_binding, sip->si_sid,
29911102SGavin.Maltby@Sun.COM 	    sip->si_pat, fmev_proxy_cb, sip, 0, ihdl->sh_attr)) != 0) {
30011102SGavin.Maltby@Sun.COM 		fmev_err_t err;
30111102SGavin.Maltby@Sun.COM 
30211102SGavin.Maltby@Sun.COM 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
30311102SGavin.Maltby@Sun.COM 		fmev_shdl_free(hdl, sip, sizeof (*sip));
30411102SGavin.Maltby@Sun.COM 
30511102SGavin.Maltby@Sun.COM 		switch (serr) {
30611102SGavin.Maltby@Sun.COM 		case ENOMEM:
30711102SGavin.Maltby@Sun.COM 			err = FMEVERR_MAX_SUBSCRIBERS;
30811102SGavin.Maltby@Sun.COM 			break;
30911102SGavin.Maltby@Sun.COM 
31011102SGavin.Maltby@Sun.COM 		default:
31111102SGavin.Maltby@Sun.COM 			err = FMEVERR_INTERNAL;
31211102SGavin.Maltby@Sun.COM 			break;
31311102SGavin.Maltby@Sun.COM 		}
31411102SGavin.Maltby@Sun.COM 
31511102SGavin.Maltby@Sun.COM 		return (fmev_seterr(err));
31611102SGavin.Maltby@Sun.COM 	}
31711102SGavin.Maltby@Sun.COM 
31811102SGavin.Maltby@Sun.COM 	uu_avl_insert(ihdl->sh_avl, sip, idx);
31911102SGavin.Maltby@Sun.COM 	ihdl->sh_subcnt++;
32011102SGavin.Maltby@Sun.COM 
32111102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
32211102SGavin.Maltby@Sun.COM 
32311102SGavin.Maltby@Sun.COM 	return (fmev_seterr(FMEV_SUCCESS));
32411102SGavin.Maltby@Sun.COM }
32511102SGavin.Maltby@Sun.COM 
32611102SGavin.Maltby@Sun.COM static int
fmev_subinfo_fini(fmev_shdl_impl_t * ihdl,struct fmev_subinfo * sip,boolean_t doavl)32711102SGavin.Maltby@Sun.COM fmev_subinfo_fini(fmev_shdl_impl_t *ihdl, struct fmev_subinfo *sip,
32811102SGavin.Maltby@Sun.COM     boolean_t doavl)
32911102SGavin.Maltby@Sun.COM {
33011102SGavin.Maltby@Sun.COM 	int err;
33111102SGavin.Maltby@Sun.COM 
33211102SGavin.Maltby@Sun.COM 	ASSERT(sip->si_ihdl == ihdl);
33311102SGavin.Maltby@Sun.COM 
33411102SGavin.Maltby@Sun.COM 	err = sysevent_evc_unsubscribe(ihdl->sh_binding, sip->si_sid);
33511102SGavin.Maltby@Sun.COM 
33611102SGavin.Maltby@Sun.COM 	if (err == 0) {
33711102SGavin.Maltby@Sun.COM 		if (doavl) {
33811102SGavin.Maltby@Sun.COM 			uu_avl_remove(ihdl->sh_avl, sip);
33911102SGavin.Maltby@Sun.COM 			uu_avl_node_fini(sip, &sip->si_node, ihdl->sh_pool);
34011102SGavin.Maltby@Sun.COM 		}
34111102SGavin.Maltby@Sun.COM 		fmev_shdl_free(IHDL2HDL(ihdl), sip, sizeof (*sip));
34211102SGavin.Maltby@Sun.COM 		ihdl->sh_subcnt--;
34311102SGavin.Maltby@Sun.COM 	}
34411102SGavin.Maltby@Sun.COM 
34511102SGavin.Maltby@Sun.COM 	return (err);
34611102SGavin.Maltby@Sun.COM }
34711102SGavin.Maltby@Sun.COM 
34811102SGavin.Maltby@Sun.COM fmev_err_t
fmev_shdl_unsubscribe(fmev_shdl_t hdl,const char * pat)34911102SGavin.Maltby@Sun.COM fmev_shdl_unsubscribe(fmev_shdl_t hdl, const char *pat)
35011102SGavin.Maltby@Sun.COM {
35111102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
35211102SGavin.Maltby@Sun.COM 	fmev_err_t rv = FMEVERR_NOMATCH;
35311102SGavin.Maltby@Sun.COM 	struct fmev_subinfo *sip;
35411102SGavin.Maltby@Sun.COM 	struct fmev_subinfo si;
35511102SGavin.Maltby@Sun.COM 	int err;
35611102SGavin.Maltby@Sun.COM 
357*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
35811102SGavin.Maltby@Sun.COM 		return (fmev_errno);
35911102SGavin.Maltby@Sun.COM 
36011102SGavin.Maltby@Sun.COM 	if (pat == NULL)
36111102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_API));
36211102SGavin.Maltby@Sun.COM 
36311102SGavin.Maltby@Sun.COM 	if (*pat == '\0' || strncmp(pat, EVCH_ALLSUB, sizeof (EC_ALL)) == 0 ||
36411102SGavin.Maltby@Sun.COM 	    strnlen(pat, FMEV_MAX_CLASS) == FMEV_MAX_CLASS)
36511102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_BADCLASS));
36611102SGavin.Maltby@Sun.COM 
36711102SGavin.Maltby@Sun.COM 	(void) strncpy(si.si_pat, pat, sizeof (si.si_pat));
36811102SGavin.Maltby@Sun.COM 
36911102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_lock(&ihdl->sh_lock);
37011102SGavin.Maltby@Sun.COM 
37111102SGavin.Maltby@Sun.COM 	if ((sip = uu_avl_find(ihdl->sh_avl, &si, NULL, NULL)) != NULL) {
37211102SGavin.Maltby@Sun.COM 		if ((err = fmev_subinfo_fini(ihdl, sip, B_TRUE)) == 0) {
37311102SGavin.Maltby@Sun.COM 			rv = FMEV_SUCCESS;
37411102SGavin.Maltby@Sun.COM 		} else {
37511102SGavin.Maltby@Sun.COM 			/*
37611102SGavin.Maltby@Sun.COM 			 * Return an API error if the unsubscribe was
37711102SGavin.Maltby@Sun.COM 			 * attempted from within a door callback invocation;
37811102SGavin.Maltby@Sun.COM 			 * other errors should not happen.
37911102SGavin.Maltby@Sun.COM 			 */
38011102SGavin.Maltby@Sun.COM 			rv = (err == EDEADLK) ? FMEVERR_API : FMEVERR_INTERNAL;
38111102SGavin.Maltby@Sun.COM 		}
38211102SGavin.Maltby@Sun.COM 	}
38311102SGavin.Maltby@Sun.COM 
38411102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
38511102SGavin.Maltby@Sun.COM 
38611102SGavin.Maltby@Sun.COM 	return (fmev_seterr(rv));
38711102SGavin.Maltby@Sun.COM }
38811102SGavin.Maltby@Sun.COM 
38911102SGavin.Maltby@Sun.COM void *
fmev_shdl_alloc(fmev_shdl_t hdl,size_t sz)39011102SGavin.Maltby@Sun.COM fmev_shdl_alloc(fmev_shdl_t hdl, size_t sz)
39111102SGavin.Maltby@Sun.COM {
39211102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
39311102SGavin.Maltby@Sun.COM 
394*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
395*12967Sgavin.maltby@oracle.com 		return (NULL);
39611102SGavin.Maltby@Sun.COM 
39711102SGavin.Maltby@Sun.COM 	return (ihdl->sh_cmn.hc_alloc(sz));
39811102SGavin.Maltby@Sun.COM }
39911102SGavin.Maltby@Sun.COM 
40011102SGavin.Maltby@Sun.COM void *
fmev_shdl_zalloc(fmev_shdl_t hdl,size_t sz)40111102SGavin.Maltby@Sun.COM fmev_shdl_zalloc(fmev_shdl_t hdl, size_t sz)
40211102SGavin.Maltby@Sun.COM {
40311102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
40411102SGavin.Maltby@Sun.COM 
405*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
406*12967Sgavin.maltby@oracle.com 		return (NULL);
40711102SGavin.Maltby@Sun.COM 
40811102SGavin.Maltby@Sun.COM 	return (ihdl->sh_cmn.hc_zalloc(sz));
40911102SGavin.Maltby@Sun.COM }
41011102SGavin.Maltby@Sun.COM 
41111102SGavin.Maltby@Sun.COM void
fmev_shdl_free(fmev_shdl_t hdl,void * buf,size_t sz)41211102SGavin.Maltby@Sun.COM fmev_shdl_free(fmev_shdl_t hdl, void *buf, size_t sz)
41311102SGavin.Maltby@Sun.COM {
41411102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
41511102SGavin.Maltby@Sun.COM 
416*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
417*12967Sgavin.maltby@oracle.com 		return;
41811102SGavin.Maltby@Sun.COM 
41911102SGavin.Maltby@Sun.COM 	ihdl->sh_cmn.hc_free(buf, sz);
42011102SGavin.Maltby@Sun.COM }
42111102SGavin.Maltby@Sun.COM 
422*12967Sgavin.maltby@oracle.com char *
fmev_shdl_strdup(fmev_shdl_t hdl,char * src)423*12967Sgavin.maltby@oracle.com fmev_shdl_strdup(fmev_shdl_t hdl, char *src)
424*12967Sgavin.maltby@oracle.com {
425*12967Sgavin.maltby@oracle.com 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
426*12967Sgavin.maltby@oracle.com 	size_t srclen;
427*12967Sgavin.maltby@oracle.com 	char *dst;
428*12967Sgavin.maltby@oracle.com 
429*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 2))
430*12967Sgavin.maltby@oracle.com 		return (NULL);
431*12967Sgavin.maltby@oracle.com 
432*12967Sgavin.maltby@oracle.com 	srclen = strlen(src);
433*12967Sgavin.maltby@oracle.com 
434*12967Sgavin.maltby@oracle.com 	if ((dst = ihdl->sh_cmn.hc_alloc(srclen + 1)) == NULL) {
435*12967Sgavin.maltby@oracle.com 		(void) fmev_seterr(FMEVERR_ALLOC);
436*12967Sgavin.maltby@oracle.com 		return (NULL);
437*12967Sgavin.maltby@oracle.com 	}
438*12967Sgavin.maltby@oracle.com 
439*12967Sgavin.maltby@oracle.com 	(void) strncpy(dst, src, srclen);
440*12967Sgavin.maltby@oracle.com 	dst[srclen] = '\0';
441*12967Sgavin.maltby@oracle.com 	return (dst);
442*12967Sgavin.maltby@oracle.com }
443*12967Sgavin.maltby@oracle.com 
444*12967Sgavin.maltby@oracle.com void
fmev_shdl_strfree(fmev_shdl_t hdl,char * buf)445*12967Sgavin.maltby@oracle.com fmev_shdl_strfree(fmev_shdl_t hdl, char *buf)
446*12967Sgavin.maltby@oracle.com {
447*12967Sgavin.maltby@oracle.com 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
448*12967Sgavin.maltby@oracle.com 
449*12967Sgavin.maltby@oracle.com 	(void) FMEV_API_ENTER(hdl, 2);
450*12967Sgavin.maltby@oracle.com 
451*12967Sgavin.maltby@oracle.com 	ihdl->sh_cmn.hc_free(buf, strlen(buf) + 1);
452*12967Sgavin.maltby@oracle.com }
453*12967Sgavin.maltby@oracle.com 
45411102SGavin.Maltby@Sun.COM int
fmev_shdl_valid(fmev_shdl_t hdl)45511102SGavin.Maltby@Sun.COM fmev_shdl_valid(fmev_shdl_t hdl)
45611102SGavin.Maltby@Sun.COM {
45711102SGavin.Maltby@Sun.COM 	return (FMEV_SHDL_VALID(HDL2IHDL(hdl)));
45811102SGavin.Maltby@Sun.COM }
45911102SGavin.Maltby@Sun.COM 
46011102SGavin.Maltby@Sun.COM /*ARGSUSED*/
46111102SGavin.Maltby@Sun.COM static int
fmev_keycmp(const void * l,const void * r,void * arg)46211102SGavin.Maltby@Sun.COM fmev_keycmp(const void *l, const void *r, void *arg)
46311102SGavin.Maltby@Sun.COM {
46411102SGavin.Maltby@Sun.COM 	struct fmev_subinfo *left = (struct fmev_subinfo *)l;
46511102SGavin.Maltby@Sun.COM 	struct fmev_subinfo *right = (struct fmev_subinfo *)r;
46611102SGavin.Maltby@Sun.COM 
46711102SGavin.Maltby@Sun.COM 	return (strncmp(left->si_pat, right->si_pat, FMEV_MAX_CLASS));
46811102SGavin.Maltby@Sun.COM }
46911102SGavin.Maltby@Sun.COM 
47011102SGavin.Maltby@Sun.COM fmev_shdl_t
fmev_shdl_init(uint32_t caller_version,void * (* hdlalloc)(size_t),void * (* hdlzalloc)(size_t),void (* hdlfree)(void *,size_t))47111102SGavin.Maltby@Sun.COM fmev_shdl_init(uint32_t caller_version, void *(*hdlalloc)(size_t),
47211102SGavin.Maltby@Sun.COM     void *(*hdlzalloc)(size_t), void (*hdlfree)(void *, size_t))
47311102SGavin.Maltby@Sun.COM {
47411102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl;
47511102SGavin.Maltby@Sun.COM 	struct fmev_hdl_cmn hc;
47611102SGavin.Maltby@Sun.COM 	const char *chan_name;
47711102SGavin.Maltby@Sun.COM 	int err;
47811102SGavin.Maltby@Sun.COM 
47911102SGavin.Maltby@Sun.COM 	hc.hc_magic = _FMEV_SHMAGIC;
48011102SGavin.Maltby@Sun.COM 	hc.hc_api_vers = caller_version;
48111102SGavin.Maltby@Sun.COM 	hc.hc_alloc = hdlalloc ? hdlalloc : dflt_alloc;
48211102SGavin.Maltby@Sun.COM 	hc.hc_zalloc = hdlzalloc ? hdlzalloc : dflt_zalloc;
48311102SGavin.Maltby@Sun.COM 	hc.hc_free = hdlfree ? hdlfree : dflt_free;
48411102SGavin.Maltby@Sun.COM 
48511102SGavin.Maltby@Sun.COM 	if (!fmev_api_init(&hc))
48611102SGavin.Maltby@Sun.COM 		return (NULL);	/* error type set */
48711102SGavin.Maltby@Sun.COM 
48811102SGavin.Maltby@Sun.COM 	if (!((hdlalloc == NULL && hdlzalloc == NULL && hdlfree == NULL) ||
48911102SGavin.Maltby@Sun.COM 	    (hdlalloc != NULL && hdlzalloc != NULL && hdlfree != NULL))) {
49011102SGavin.Maltby@Sun.COM 		(void) fmev_seterr(FMEVERR_API);
49111102SGavin.Maltby@Sun.COM 		return (NULL);
49211102SGavin.Maltby@Sun.COM 	}
49311102SGavin.Maltby@Sun.COM 
49411102SGavin.Maltby@Sun.COM 	if (hdlzalloc == NULL)
49511102SGavin.Maltby@Sun.COM 		ihdl = dflt_zalloc(sizeof (*ihdl));
49611102SGavin.Maltby@Sun.COM 	else
49711102SGavin.Maltby@Sun.COM 		ihdl = hdlzalloc(sizeof (*ihdl));
49811102SGavin.Maltby@Sun.COM 
49911102SGavin.Maltby@Sun.COM 	if (ihdl == NULL) {
50011102SGavin.Maltby@Sun.COM 		(void) fmev_seterr(FMEVERR_ALLOC);
50111102SGavin.Maltby@Sun.COM 		return (NULL);
50211102SGavin.Maltby@Sun.COM 	}
50311102SGavin.Maltby@Sun.COM 
50411102SGavin.Maltby@Sun.COM 	ihdl->sh_cmn = hc;
50511102SGavin.Maltby@Sun.COM 
50611102SGavin.Maltby@Sun.COM 	if ((ihdl->sh_attr = sysevent_subattr_alloc()) == NULL) {
50711102SGavin.Maltby@Sun.COM 		err = FMEVERR_ALLOC;
50811102SGavin.Maltby@Sun.COM 		goto error;
50911102SGavin.Maltby@Sun.COM 	}
51011102SGavin.Maltby@Sun.COM 
51111102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_init(&ihdl->sh_lock, NULL);
51211102SGavin.Maltby@Sun.COM 
51311102SGavin.Maltby@Sun.COM 	/*
51411102SGavin.Maltby@Sun.COM 	 * For simulation purposes we allow an environment variable
51511102SGavin.Maltby@Sun.COM 	 * to provide a different channel name.
51611102SGavin.Maltby@Sun.COM 	 */
51711102SGavin.Maltby@Sun.COM 	if ((chan_name = getenv("FMD_SNOOP_CHANNEL")) == NULL)
51811102SGavin.Maltby@Sun.COM 		chan_name = FMD_SNOOP_CHANNEL;
51911102SGavin.Maltby@Sun.COM 
52011102SGavin.Maltby@Sun.COM 	/*
52111102SGavin.Maltby@Sun.COM 	 * Try to bind to the event channel. If it's not already present,
52211102SGavin.Maltby@Sun.COM 	 * attempt to create the channel so that we can startup before
52311102SGavin.Maltby@Sun.COM 	 * the event producer (who will also apply choices such as
52411102SGavin.Maltby@Sun.COM 	 * channel depth when they bind to the channel).
52511102SGavin.Maltby@Sun.COM 	 */
52611102SGavin.Maltby@Sun.COM 	if (sysevent_evc_bind(chan_name, &ihdl->sh_binding,
52711102SGavin.Maltby@Sun.COM 	    EVCH_CREAT | EVCH_HOLD_PEND_INDEF) != 0) {
52811102SGavin.Maltby@Sun.COM 		switch (errno) {
52911102SGavin.Maltby@Sun.COM 		case EINVAL:
53011102SGavin.Maltby@Sun.COM 		default:
53111102SGavin.Maltby@Sun.COM 			err = FMEVERR_INTERNAL;
53211102SGavin.Maltby@Sun.COM 			break;
53311102SGavin.Maltby@Sun.COM 		case ENOMEM:
53411102SGavin.Maltby@Sun.COM 			err = FMEVERR_ALLOC;
53511102SGavin.Maltby@Sun.COM 			break;
53611102SGavin.Maltby@Sun.COM 		case EPERM:
53711102SGavin.Maltby@Sun.COM 			err = FMEVERR_NOPRIV;
53811102SGavin.Maltby@Sun.COM 			break;
53911102SGavin.Maltby@Sun.COM 		}
54011102SGavin.Maltby@Sun.COM 		goto error;
54111102SGavin.Maltby@Sun.COM 	}
54211102SGavin.Maltby@Sun.COM 
54311102SGavin.Maltby@Sun.COM 	if ((ihdl->sh_pool = uu_avl_pool_create("subinfo_pool",
54411102SGavin.Maltby@Sun.COM 	    sizeof (struct fmev_subinfo),
54511102SGavin.Maltby@Sun.COM 	    offsetof(struct fmev_subinfo, si_node), fmev_keycmp,
54611102SGavin.Maltby@Sun.COM 	    UU_AVL_POOL_DEBUG)) == NULL) {
54711102SGavin.Maltby@Sun.COM 		err = FMEVERR_INTERNAL;
54811102SGavin.Maltby@Sun.COM 		goto error;
54911102SGavin.Maltby@Sun.COM 	}
55011102SGavin.Maltby@Sun.COM 
55111102SGavin.Maltby@Sun.COM 	if ((ihdl->sh_avl = uu_avl_create(ihdl->sh_pool, NULL,
55211102SGavin.Maltby@Sun.COM 	    UU_DEFAULT)) == NULL) {
55311102SGavin.Maltby@Sun.COM 		err = FMEVERR_INTERNAL;
55411102SGavin.Maltby@Sun.COM 		goto error;
55511102SGavin.Maltby@Sun.COM 	}
55611102SGavin.Maltby@Sun.COM 
55711102SGavin.Maltby@Sun.COM 	return (IHDL2HDL(ihdl));
55811102SGavin.Maltby@Sun.COM 
55911102SGavin.Maltby@Sun.COM error:
56011102SGavin.Maltby@Sun.COM 	(void) fmev_shdl_fini(IHDL2HDL(ihdl));
56111102SGavin.Maltby@Sun.COM 	(void) fmev_seterr(err);
56211102SGavin.Maltby@Sun.COM 	return (NULL);
56311102SGavin.Maltby@Sun.COM }
56411102SGavin.Maltby@Sun.COM 
56511102SGavin.Maltby@Sun.COM fmev_err_t
fmev_shdl_getauthority(fmev_shdl_t hdl,nvlist_t ** nvlp)566*12967Sgavin.maltby@oracle.com fmev_shdl_getauthority(fmev_shdl_t hdl, nvlist_t **nvlp)
567*12967Sgavin.maltby@oracle.com {
568*12967Sgavin.maltby@oracle.com 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
569*12967Sgavin.maltby@oracle.com 	nvlist_t *propnvl;
570*12967Sgavin.maltby@oracle.com 	fmev_err_t rc;
571*12967Sgavin.maltby@oracle.com 
572*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 2))
573*12967Sgavin.maltby@oracle.com 		return (fmev_errno);
574*12967Sgavin.maltby@oracle.com 
575*12967Sgavin.maltby@oracle.com 	(void) pthread_mutex_lock(&ihdl->sh_lock);
576*12967Sgavin.maltby@oracle.com 
577*12967Sgavin.maltby@oracle.com 	if (sysevent_evc_getpropnvl(ihdl->sh_binding, &propnvl) != 0) {
578*12967Sgavin.maltby@oracle.com 		*nvlp = NULL;
579*12967Sgavin.maltby@oracle.com 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
580*12967Sgavin.maltby@oracle.com 		return (fmev_seterr(FMEVERR_UNKNOWN));
581*12967Sgavin.maltby@oracle.com 	}
582*12967Sgavin.maltby@oracle.com 
583*12967Sgavin.maltby@oracle.com 	if (propnvl == NULL) {
584*12967Sgavin.maltby@oracle.com 		rc = FMEVERR_BUSY;	/* Other end has not bound */
585*12967Sgavin.maltby@oracle.com 	} else {
586*12967Sgavin.maltby@oracle.com 		nvlist_t *auth;
587*12967Sgavin.maltby@oracle.com 
588*12967Sgavin.maltby@oracle.com 		if (nvlist_lookup_nvlist(propnvl, "fmdauth", &auth) == 0) {
589*12967Sgavin.maltby@oracle.com 			rc = (nvlist_dup(auth, nvlp, 0) == 0) ? FMEV_SUCCESS :
590*12967Sgavin.maltby@oracle.com 			    FMEVERR_ALLOC;
591*12967Sgavin.maltby@oracle.com 		} else {
592*12967Sgavin.maltby@oracle.com 			rc = FMEVERR_INTERNAL;
593*12967Sgavin.maltby@oracle.com 		}
594*12967Sgavin.maltby@oracle.com 		nvlist_free(propnvl);
595*12967Sgavin.maltby@oracle.com 	}
596*12967Sgavin.maltby@oracle.com 
597*12967Sgavin.maltby@oracle.com 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
598*12967Sgavin.maltby@oracle.com 
599*12967Sgavin.maltby@oracle.com 	if (rc != FMEV_SUCCESS) {
600*12967Sgavin.maltby@oracle.com 		*nvlp = NULL;
601*12967Sgavin.maltby@oracle.com 		(void) fmev_seterr(rc);
602*12967Sgavin.maltby@oracle.com 	}
603*12967Sgavin.maltby@oracle.com 
604*12967Sgavin.maltby@oracle.com 	return (rc);
605*12967Sgavin.maltby@oracle.com }
606*12967Sgavin.maltby@oracle.com 
607*12967Sgavin.maltby@oracle.com char *
fmev_shdl_nvl2str(fmev_shdl_t hdl,nvlist_t * nvl)608*12967Sgavin.maltby@oracle.com fmev_shdl_nvl2str(fmev_shdl_t hdl, nvlist_t *nvl)
609*12967Sgavin.maltby@oracle.com {
610*12967Sgavin.maltby@oracle.com 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
611*12967Sgavin.maltby@oracle.com 	char *fmri, *fmricp;
612*12967Sgavin.maltby@oracle.com 	fmev_err_t err;
613*12967Sgavin.maltby@oracle.com 	int topoerr;
614*12967Sgavin.maltby@oracle.com 
615*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 2))
616*12967Sgavin.maltby@oracle.com 		return (NULL);
617*12967Sgavin.maltby@oracle.com 
618*12967Sgavin.maltby@oracle.com 	if (g_topohdl == NULL) {
619*12967Sgavin.maltby@oracle.com 		(void) pthread_mutex_lock(&ihdl->sh_lock);
620*12967Sgavin.maltby@oracle.com 		if (g_topohdl == NULL)
621*12967Sgavin.maltby@oracle.com 			g_topohdl = topo_open(TOPO_VERSION, NULL, &topoerr);
622*12967Sgavin.maltby@oracle.com 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
623*12967Sgavin.maltby@oracle.com 
624*12967Sgavin.maltby@oracle.com 		if (g_topohdl == NULL) {
625*12967Sgavin.maltby@oracle.com 			(void) fmev_seterr(FMEVERR_INTERNAL);
626*12967Sgavin.maltby@oracle.com 			return (NULL);
627*12967Sgavin.maltby@oracle.com 		}
628*12967Sgavin.maltby@oracle.com 	}
629*12967Sgavin.maltby@oracle.com 
630*12967Sgavin.maltby@oracle.com 	if (topo_fmri_nvl2str(g_topohdl, nvl, &fmri, &topoerr) == 0) {
631*12967Sgavin.maltby@oracle.com 		fmricp = fmev_shdl_strdup(hdl, fmri);
632*12967Sgavin.maltby@oracle.com 		topo_hdl_strfree(g_topohdl, fmri);
633*12967Sgavin.maltby@oracle.com 		return (fmricp);	/* fmev_errno set if strdup failed */
634*12967Sgavin.maltby@oracle.com 	}
635*12967Sgavin.maltby@oracle.com 
636*12967Sgavin.maltby@oracle.com 	switch (topoerr) {
637*12967Sgavin.maltby@oracle.com 	case ETOPO_FMRI_NOMEM:
638*12967Sgavin.maltby@oracle.com 		err = FMEVERR_ALLOC;
639*12967Sgavin.maltby@oracle.com 		break;
640*12967Sgavin.maltby@oracle.com 
641*12967Sgavin.maltby@oracle.com 	case ETOPO_FMRI_MALFORM:
642*12967Sgavin.maltby@oracle.com 	case ETOPO_METHOD_NOTSUP:
643*12967Sgavin.maltby@oracle.com 	case ETOPO_METHOD_INVAL:
644*12967Sgavin.maltby@oracle.com 	default:
645*12967Sgavin.maltby@oracle.com 		err = FMEVERR_INVALIDARG;
646*12967Sgavin.maltby@oracle.com 		break;
647*12967Sgavin.maltby@oracle.com 	}
648*12967Sgavin.maltby@oracle.com 
649*12967Sgavin.maltby@oracle.com 	(void) fmev_seterr(err);
650*12967Sgavin.maltby@oracle.com 	return (NULL);
651*12967Sgavin.maltby@oracle.com }
652*12967Sgavin.maltby@oracle.com 
653*12967Sgavin.maltby@oracle.com fmev_err_t
fmev_shdl_fini(fmev_shdl_t hdl)65411102SGavin.Maltby@Sun.COM fmev_shdl_fini(fmev_shdl_t hdl)
65511102SGavin.Maltby@Sun.COM {
65611102SGavin.Maltby@Sun.COM 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
65711102SGavin.Maltby@Sun.COM 
658*12967Sgavin.maltby@oracle.com 	if (!FMEV_API_ENTER(hdl, 1))
659*12967Sgavin.maltby@oracle.com 		return (fmev_errno);
66011102SGavin.Maltby@Sun.COM 
66111102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_lock(&ihdl->sh_lock);
66211102SGavin.Maltby@Sun.COM 
66311102SGavin.Maltby@Sun.COM 	/*
66411102SGavin.Maltby@Sun.COM 	 * Verify that we are not in callback context - return an API
66511102SGavin.Maltby@Sun.COM 	 * error if we are.
66611102SGavin.Maltby@Sun.COM 	 */
66711102SGavin.Maltby@Sun.COM 	if (sysevent_evc_unsubscribe(ihdl->sh_binding, "invalidsid") ==
66811102SGavin.Maltby@Sun.COM 	    EDEADLK) {
66911102SGavin.Maltby@Sun.COM 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
67011102SGavin.Maltby@Sun.COM 		return (fmev_seterr(FMEVERR_API));
67111102SGavin.Maltby@Sun.COM 	}
67211102SGavin.Maltby@Sun.COM 
67311102SGavin.Maltby@Sun.COM 	if (ihdl->sh_avl) {
67411102SGavin.Maltby@Sun.COM 		void *cookie = NULL;
67511102SGavin.Maltby@Sun.COM 		struct fmev_subinfo *sip;
67611102SGavin.Maltby@Sun.COM 
67711102SGavin.Maltby@Sun.COM 		while ((sip = uu_avl_teardown(ihdl->sh_avl, &cookie)) != NULL)
67811102SGavin.Maltby@Sun.COM 			(void) fmev_subinfo_fini(ihdl, sip, B_FALSE);
67911102SGavin.Maltby@Sun.COM 
68011102SGavin.Maltby@Sun.COM 		uu_avl_destroy(ihdl->sh_avl);
68111102SGavin.Maltby@Sun.COM 		ihdl->sh_avl = NULL;
68211102SGavin.Maltby@Sun.COM 	}
68311102SGavin.Maltby@Sun.COM 
68411102SGavin.Maltby@Sun.COM 	ASSERT(ihdl->sh_subcnt == 0);
68511102SGavin.Maltby@Sun.COM 
68611102SGavin.Maltby@Sun.COM 	if (ihdl->sh_binding) {
68711102SGavin.Maltby@Sun.COM 		(void) sysevent_evc_unbind(ihdl->sh_binding);
68811102SGavin.Maltby@Sun.COM 		ihdl->sh_binding = NULL;
68911102SGavin.Maltby@Sun.COM 	}
69011102SGavin.Maltby@Sun.COM 
69111102SGavin.Maltby@Sun.COM 	if (ihdl->sh_pool) {
69211102SGavin.Maltby@Sun.COM 		uu_avl_pool_destroy(ihdl->sh_pool);
69311102SGavin.Maltby@Sun.COM 		ihdl->sh_pool = NULL;
69411102SGavin.Maltby@Sun.COM 	}
69511102SGavin.Maltby@Sun.COM 
69611102SGavin.Maltby@Sun.COM 	if (ihdl->sh_attr) {
69711102SGavin.Maltby@Sun.COM 		sysevent_subattr_free(ihdl->sh_attr);
69811102SGavin.Maltby@Sun.COM 		ihdl->sh_attr = NULL;
69911102SGavin.Maltby@Sun.COM 	}
70011102SGavin.Maltby@Sun.COM 
70111102SGavin.Maltby@Sun.COM 	ihdl->sh_cmn.hc_magic = 0;
70211102SGavin.Maltby@Sun.COM 
703*12967Sgavin.maltby@oracle.com 	if (g_topohdl) {
704*12967Sgavin.maltby@oracle.com 		topo_close(g_topohdl);
705*12967Sgavin.maltby@oracle.com 		g_topohdl = NULL;
706*12967Sgavin.maltby@oracle.com 	}
707*12967Sgavin.maltby@oracle.com 
70811102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
70911102SGavin.Maltby@Sun.COM 	(void) pthread_mutex_destroy(&ihdl->sh_lock);
71011102SGavin.Maltby@Sun.COM 
71111102SGavin.Maltby@Sun.COM 	fmev_shdl_free(hdl, hdl, sizeof (*ihdl));
71211102SGavin.Maltby@Sun.COM 
71311102SGavin.Maltby@Sun.COM 	fmev_api_freetsd();
71411102SGavin.Maltby@Sun.COM 
71511102SGavin.Maltby@Sun.COM 	return (fmev_seterr(FMEV_SUCCESS));
71611102SGavin.Maltby@Sun.COM }
717