1*12967Sgavin.maltby@oracle.com /*
2*12967Sgavin.maltby@oracle.com  * CDDL HEADER START
3*12967Sgavin.maltby@oracle.com  *
4*12967Sgavin.maltby@oracle.com  * The contents of this file are subject to the terms of the
5*12967Sgavin.maltby@oracle.com  * Common Development and Distribution License (the "License").
6*12967Sgavin.maltby@oracle.com  * You may not use this file except in compliance with the License.
7*12967Sgavin.maltby@oracle.com  *
8*12967Sgavin.maltby@oracle.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12967Sgavin.maltby@oracle.com  * or http://www.opensolaris.org/os/licensing.
10*12967Sgavin.maltby@oracle.com  * See the License for the specific language governing permissions
11*12967Sgavin.maltby@oracle.com  * and limitations under the License.
12*12967Sgavin.maltby@oracle.com  *
13*12967Sgavin.maltby@oracle.com  * When distributing Covered Code, include this CDDL HEADER in each
14*12967Sgavin.maltby@oracle.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12967Sgavin.maltby@oracle.com  * If applicable, add the following below this CDDL HEADER, with the
16*12967Sgavin.maltby@oracle.com  * fields enclosed by brackets "[]" replaced with your own identifying
17*12967Sgavin.maltby@oracle.com  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12967Sgavin.maltby@oracle.com  *
19*12967Sgavin.maltby@oracle.com  * CDDL HEADER END
20*12967Sgavin.maltby@oracle.com  */
21*12967Sgavin.maltby@oracle.com 
22*12967Sgavin.maltby@oracle.com /*
23*12967Sgavin.maltby@oracle.com  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*12967Sgavin.maltby@oracle.com  */
25*12967Sgavin.maltby@oracle.com 
26*12967Sgavin.maltby@oracle.com /*
27*12967Sgavin.maltby@oracle.com  * Receive (on GPEC channels) raw events published by a few select producers
28*12967Sgavin.maltby@oracle.com  * using the private libfmevent publication interfaces, and massage those
29*12967Sgavin.maltby@oracle.com  * raw events into full protocol events.  Each raw event selects a "ruleset"
30*12967Sgavin.maltby@oracle.com  * by which to perform the transformation into a protocol event.
31*12967Sgavin.maltby@oracle.com  *
32*12967Sgavin.maltby@oracle.com  * Only publication from userland running privileged is supported; two
33*12967Sgavin.maltby@oracle.com  * channels are used - one for high-value and one for low-value events.
34*12967Sgavin.maltby@oracle.com  * There is some planning in the implementation below for kernel hi and low
35*12967Sgavin.maltby@oracle.com  * value channels, and for non-privileged userland low and hi value channels.
36*12967Sgavin.maltby@oracle.com  */
37*12967Sgavin.maltby@oracle.com 
38*12967Sgavin.maltby@oracle.com #include <fm/fmd_api.h>
39*12967Sgavin.maltby@oracle.com #include <fm/libfmevent.h>
40*12967Sgavin.maltby@oracle.com #include <uuid/uuid.h>
41*12967Sgavin.maltby@oracle.com #include <libsysevent.h>
42*12967Sgavin.maltby@oracle.com #include <pthread.h>
43*12967Sgavin.maltby@oracle.com #include <libnvpair.h>
44*12967Sgavin.maltby@oracle.com #include <strings.h>
45*12967Sgavin.maltby@oracle.com #include <zone.h>
46*12967Sgavin.maltby@oracle.com 
47*12967Sgavin.maltby@oracle.com #include "fmevt.h"
48*12967Sgavin.maltby@oracle.com 
49*12967Sgavin.maltby@oracle.com static struct fmevt_inbound_stats {
50*12967Sgavin.maltby@oracle.com 	fmd_stat_t raw_callbacks;
51*12967Sgavin.maltby@oracle.com 	fmd_stat_t raw_noattrlist;
52*12967Sgavin.maltby@oracle.com 	fmd_stat_t raw_nodetector;
53*12967Sgavin.maltby@oracle.com 	fmd_stat_t pp_bad_ruleset;
54*12967Sgavin.maltby@oracle.com 	fmd_stat_t pp_explicitdrop;
55*12967Sgavin.maltby@oracle.com 	fmd_stat_t pp_fallthrurule;
56*12967Sgavin.maltby@oracle.com 	fmd_stat_t pp_fanoutmax;
57*12967Sgavin.maltby@oracle.com 	fmd_stat_t pp_intldrop;
58*12967Sgavin.maltby@oracle.com 	fmd_stat_t pp_badclass;
59*12967Sgavin.maltby@oracle.com 	fmd_stat_t pp_nvlallocfail;
60*12967Sgavin.maltby@oracle.com 	fmd_stat_t pp_nvlbuildfail;
61*12967Sgavin.maltby@oracle.com 	fmd_stat_t pp_badreturn;
62*12967Sgavin.maltby@oracle.com 	fmd_stat_t xprt_posted;
63*12967Sgavin.maltby@oracle.com } inbound_stats = {
64*12967Sgavin.maltby@oracle.com 	{ "raw_callbacks", FMD_TYPE_UINT64,
65*12967Sgavin.maltby@oracle.com 	    "total raw event callbacks from producers" },
66*12967Sgavin.maltby@oracle.com 	{ "raw_noattrlist", FMD_TYPE_UINT64,
67*12967Sgavin.maltby@oracle.com 	    "missing attribute list" },
68*12967Sgavin.maltby@oracle.com 	{ "raw_nodetector", FMD_TYPE_UINT64,
69*12967Sgavin.maltby@oracle.com 	    "unable to add detector" },
70*12967Sgavin.maltby@oracle.com 	{ "pp_bad_ruleset", FMD_TYPE_UINT64,
71*12967Sgavin.maltby@oracle.com 	    "post-process bad ruleset" },
72*12967Sgavin.maltby@oracle.com 	{ "pp_explicitdrop", FMD_TYPE_UINT64,
73*12967Sgavin.maltby@oracle.com 	    "ruleset drops event with NULL func" },
74*12967Sgavin.maltby@oracle.com 	{ "pp_fanoutmax", FMD_TYPE_UINT64,
75*12967Sgavin.maltby@oracle.com 	    "post-processing produced too many events" },
76*12967Sgavin.maltby@oracle.com 	{ "pp_intldrop", FMD_TYPE_UINT64,
77*12967Sgavin.maltby@oracle.com 	    "post-processing requested event drop" },
78*12967Sgavin.maltby@oracle.com 	{ "pp_badclass", FMD_TYPE_UINT64,
79*12967Sgavin.maltby@oracle.com 	    "post-processing produced invalid event class" },
80*12967Sgavin.maltby@oracle.com 	{ "pp_nvlallocfail", FMD_TYPE_UINT64,
81*12967Sgavin.maltby@oracle.com 	    "fmd_nvl_alloc failed" },
82*12967Sgavin.maltby@oracle.com 	{ "pp_nvlbuildfail", FMD_TYPE_UINT64,
83*12967Sgavin.maltby@oracle.com 	    "nvlist_add_foo failed in building event" },
84*12967Sgavin.maltby@oracle.com 	{ "pp_badreturn", FMD_TYPE_UINT64,
85*12967Sgavin.maltby@oracle.com 	    "inconsistent number of events returned" },
86*12967Sgavin.maltby@oracle.com 	{ "xprt_posted", FMD_TYPE_UINT64,
87*12967Sgavin.maltby@oracle.com 	    "protocol events posted with fmd_xprt_post" },
88*12967Sgavin.maltby@oracle.com };
89*12967Sgavin.maltby@oracle.com 
90*12967Sgavin.maltby@oracle.com static int isglobalzone;
91*12967Sgavin.maltby@oracle.com static char zonename[ZONENAME_MAX];
92*12967Sgavin.maltby@oracle.com 
93*12967Sgavin.maltby@oracle.com #define	BUMPSTAT(stat)	inbound_stats.stat.fmds_value.ui64++
94*12967Sgavin.maltby@oracle.com 
95*12967Sgavin.maltby@oracle.com #define	CBF_USER	0x1U
96*12967Sgavin.maltby@oracle.com #define	CBF_PRIV	0x2U
97*12967Sgavin.maltby@oracle.com #define	CBF_LV		0x4U
98*12967Sgavin.maltby@oracle.com #define	CBF_HV		0x8U
99*12967Sgavin.maltby@oracle.com #define	CBF_ALL		(CBF_USER | CBF_PRIV | CBF_LV | CBF_HV)
100*12967Sgavin.maltby@oracle.com 
101*12967Sgavin.maltby@oracle.com static struct fmevt_chaninfo {
102*12967Sgavin.maltby@oracle.com 	const char *ci_propname;	/* property to get channel name */
103*12967Sgavin.maltby@oracle.com 	evchan_t *ci_binding;		/* GPEC binding for this channel */
104*12967Sgavin.maltby@oracle.com 	char ci_sid[MAX_SUBID_LEN];	/* subscriber id */
105*12967Sgavin.maltby@oracle.com 	uint32_t ci_cbarg;		/* callback cookie */
106*12967Sgavin.maltby@oracle.com 	uint32_t ci_sflags;		/* subscription flags to use */
107*12967Sgavin.maltby@oracle.com } chaninfo[] = {
108*12967Sgavin.maltby@oracle.com 	{ "user_priv_highval_channel", NULL, { 0 },
109*12967Sgavin.maltby@oracle.com 		CBF_USER | CBF_PRIV | CBF_HV, EVCH_SUB_KEEP },
110*12967Sgavin.maltby@oracle.com 	{ "user_priv_lowval_channel", NULL, { 0 },
111*12967Sgavin.maltby@oracle.com 		CBF_USER | CBF_PRIV | CBF_LV, EVCH_SUB_KEEP },
112*12967Sgavin.maltby@oracle.com };
113*12967Sgavin.maltby@oracle.com 
114*12967Sgavin.maltby@oracle.com static pthread_cond_t fmevt_cv = PTHREAD_COND_INITIALIZER;
115*12967Sgavin.maltby@oracle.com static pthread_mutex_t fmevt_lock = PTHREAD_MUTEX_INITIALIZER;
116*12967Sgavin.maltby@oracle.com static int fmevt_exiting;
117*12967Sgavin.maltby@oracle.com 
118*12967Sgavin.maltby@oracle.com static fmd_xprt_t *fmevt_xprt;
119*12967Sgavin.maltby@oracle.com static uint32_t fmevt_xprt_refcnt;
120*12967Sgavin.maltby@oracle.com static sysevent_subattr_t *subattr;
121*12967Sgavin.maltby@oracle.com 
122*12967Sgavin.maltby@oracle.com /*
123*12967Sgavin.maltby@oracle.com  * Rulesets we recognize and who handles them.  Additions and changes
124*12967Sgavin.maltby@oracle.com  * must follow the Portfolio Review process.  At ths time only
125*12967Sgavin.maltby@oracle.com  * the FMEV_RULESET_ON_SUNOS and FMEVT_RULESET_SMF rulesets are
126*12967Sgavin.maltby@oracle.com  * formally recognized by that process - the others here are experimental.
127*12967Sgavin.maltby@oracle.com  */
128*12967Sgavin.maltby@oracle.com static struct fmevt_rs {
129*12967Sgavin.maltby@oracle.com 	char *rs_pat;
130*12967Sgavin.maltby@oracle.com 	fmevt_pp_func_t *rs_ppfunc;
131*12967Sgavin.maltby@oracle.com 	char *rs_namespace;
132*12967Sgavin.maltby@oracle.com 	char *rs_subsys;
133*12967Sgavin.maltby@oracle.com } rulelist[] = {
134*12967Sgavin.maltby@oracle.com 	{ FMEV_RULESET_SMF, fmevt_pp_smf },
135*12967Sgavin.maltby@oracle.com 	{ FMEV_RULESET_ON_EREPORT, fmevt_pp_on_ereport },
136*12967Sgavin.maltby@oracle.com 	{ FMEV_RULESET_ON_SUNOS, fmevt_pp_on_sunos },
137*12967Sgavin.maltby@oracle.com 	{ FMEV_RULESET_ON_PRIVATE, fmevt_pp_on_private },
138*12967Sgavin.maltby@oracle.com 	{ FMEV_RULESET_UNREGISTERED, fmevt_pp_unregistered }
139*12967Sgavin.maltby@oracle.com };
140*12967Sgavin.maltby@oracle.com 
141*12967Sgavin.maltby@oracle.com /*
142*12967Sgavin.maltby@oracle.com  * Take a ruleset specification string and separate it into namespace
143*12967Sgavin.maltby@oracle.com  * and subsystem components.
144*12967Sgavin.maltby@oracle.com  */
145*12967Sgavin.maltby@oracle.com static int
fmevt_rs_burst(fmd_hdl_t * hdl,char * ruleset,char ** nsp,char ** subsysp,boolean_t alloc)146*12967Sgavin.maltby@oracle.com fmevt_rs_burst(fmd_hdl_t *hdl, char *ruleset, char **nsp, char **subsysp,
147*12967Sgavin.maltby@oracle.com     boolean_t alloc)
148*12967Sgavin.maltby@oracle.com {
149*12967Sgavin.maltby@oracle.com 	char *ns, *s;
150*12967Sgavin.maltby@oracle.com 	size_t len;
151*12967Sgavin.maltby@oracle.com 
152*12967Sgavin.maltby@oracle.com 	if (ruleset == NULL || *ruleset == '\0' ||
153*12967Sgavin.maltby@oracle.com 	    strnlen(ruleset, FMEV_MAX_RULESET_LEN) == FMEV_MAX_RULESET_LEN)
154*12967Sgavin.maltby@oracle.com 		return (0);
155*12967Sgavin.maltby@oracle.com 
156*12967Sgavin.maltby@oracle.com 	if (alloc == B_FALSE) {
157*12967Sgavin.maltby@oracle.com 		s = ruleset;
158*12967Sgavin.maltby@oracle.com 		ns = strsep(&s, FMEV_RS_SEPARATOR);
159*12967Sgavin.maltby@oracle.com 
160*12967Sgavin.maltby@oracle.com 		if (s == NULL || s == ns + 1)
161*12967Sgavin.maltby@oracle.com 			return (0);
162*12967Sgavin.maltby@oracle.com 	} else {
163*12967Sgavin.maltby@oracle.com 		if ((s = strstr(ruleset, FMEV_RS_SEPARATOR)) == NULL ||
164*12967Sgavin.maltby@oracle.com 		    s == ruleset + strlen(ruleset) - 1)
165*12967Sgavin.maltby@oracle.com 			return (0);
166*12967Sgavin.maltby@oracle.com 
167*12967Sgavin.maltby@oracle.com 		len = s - ruleset;
168*12967Sgavin.maltby@oracle.com 
169*12967Sgavin.maltby@oracle.com 		ns = fmd_hdl_alloc(hdl, len + 1, FMD_SLEEP);
170*12967Sgavin.maltby@oracle.com 		(void) strncpy(ns, ruleset, len);
171*12967Sgavin.maltby@oracle.com 		ns[len] = '\0';
172*12967Sgavin.maltby@oracle.com 
173*12967Sgavin.maltby@oracle.com 		s++;
174*12967Sgavin.maltby@oracle.com 	}
175*12967Sgavin.maltby@oracle.com 
176*12967Sgavin.maltby@oracle.com 	if (nsp)
177*12967Sgavin.maltby@oracle.com 		*nsp = ns;	/* caller must free if alloc == B_TRUE */
178*12967Sgavin.maltby@oracle.com 
179*12967Sgavin.maltby@oracle.com 	if (subsysp)
180*12967Sgavin.maltby@oracle.com 		*subsysp = s;	/* always within original ruleset string */
181*12967Sgavin.maltby@oracle.com 
182*12967Sgavin.maltby@oracle.com 	return (1);
183*12967Sgavin.maltby@oracle.com }
184*12967Sgavin.maltby@oracle.com 
185*12967Sgavin.maltby@oracle.com static int
fmevt_rs_init(fmd_hdl_t * hdl)186*12967Sgavin.maltby@oracle.com fmevt_rs_init(fmd_hdl_t *hdl)
187*12967Sgavin.maltby@oracle.com {
188*12967Sgavin.maltby@oracle.com 	int i;
189*12967Sgavin.maltby@oracle.com 
190*12967Sgavin.maltby@oracle.com 	for (i = 0; i < sizeof (rulelist) / sizeof (rulelist[0]); i++) {
191*12967Sgavin.maltby@oracle.com 		struct fmevt_rs *rsp = &rulelist[i];
192*12967Sgavin.maltby@oracle.com 
193*12967Sgavin.maltby@oracle.com 		if (!fmevt_rs_burst(hdl, rsp->rs_pat, &rsp->rs_namespace,
194*12967Sgavin.maltby@oracle.com 		    &rsp->rs_subsys, B_TRUE))
195*12967Sgavin.maltby@oracle.com 			return (0);
196*12967Sgavin.maltby@oracle.com 	}
197*12967Sgavin.maltby@oracle.com 
198*12967Sgavin.maltby@oracle.com 	return (1);
199*12967Sgavin.maltby@oracle.com }
200*12967Sgavin.maltby@oracle.com 
201*12967Sgavin.maltby@oracle.com /*
202*12967Sgavin.maltby@oracle.com  * Construct a "sw" scheme detector FMRI.
203*12967Sgavin.maltby@oracle.com  *
204*12967Sgavin.maltby@oracle.com  * We make no use of priv or pri.
205*12967Sgavin.maltby@oracle.com  */
206*12967Sgavin.maltby@oracle.com /*ARGSUSED3*/
207*12967Sgavin.maltby@oracle.com static nvlist_t *
fmevt_detector(nvlist_t * attr,char * ruleset,int user,int priv,fmev_pri_t pri)208*12967Sgavin.maltby@oracle.com fmevt_detector(nvlist_t *attr, char *ruleset, int user, int priv,
209*12967Sgavin.maltby@oracle.com     fmev_pri_t pri)
210*12967Sgavin.maltby@oracle.com {
211*12967Sgavin.maltby@oracle.com 	char buf[FMEV_MAX_RULESET_LEN + 1];
212*12967Sgavin.maltby@oracle.com 	char *ns, *subsys;
213*12967Sgavin.maltby@oracle.com 	nvlist_t *obj, *dtcr, *site, *ctxt;
214*12967Sgavin.maltby@oracle.com 	char *execname = NULL;
215*12967Sgavin.maltby@oracle.com 	int32_t i32;
216*12967Sgavin.maltby@oracle.com 	int64_t i64;
217*12967Sgavin.maltby@oracle.com 	int err = 0;
218*12967Sgavin.maltby@oracle.com 	char *str;
219*12967Sgavin.maltby@oracle.com 
220*12967Sgavin.maltby@oracle.com 	(void) strncpy(buf, ruleset, sizeof (buf));
221*12967Sgavin.maltby@oracle.com 	if (!fmevt_rs_burst(NULL, buf, &ns, &subsys, B_FALSE))
222*12967Sgavin.maltby@oracle.com 		return (NULL);
223*12967Sgavin.maltby@oracle.com 
224*12967Sgavin.maltby@oracle.com 	obj = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP);
225*12967Sgavin.maltby@oracle.com 	dtcr = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP);
226*12967Sgavin.maltby@oracle.com 	site = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP);
227*12967Sgavin.maltby@oracle.com 	ctxt = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP);
228*12967Sgavin.maltby@oracle.com 
229*12967Sgavin.maltby@oracle.com 	if (obj == NULL || dtcr == NULL || site == NULL || ctxt == NULL) {
230*12967Sgavin.maltby@oracle.com 		err++;
231*12967Sgavin.maltby@oracle.com 		goto done;
232*12967Sgavin.maltby@oracle.com 	}
233*12967Sgavin.maltby@oracle.com 
234*12967Sgavin.maltby@oracle.com 	/*
235*12967Sgavin.maltby@oracle.com 	 * Build up 'object' nvlist.
236*12967Sgavin.maltby@oracle.com 	 */
237*12967Sgavin.maltby@oracle.com 	if (nvlist_lookup_string(attr, "__fmev_execname", &execname) == 0)
238*12967Sgavin.maltby@oracle.com 		err += nvlist_add_string(obj, FM_FMRI_SW_OBJ_PATH, execname);
239*12967Sgavin.maltby@oracle.com 
240*12967Sgavin.maltby@oracle.com 	/*
241*12967Sgavin.maltby@oracle.com 	 * Build up 'site' nvlist.  We should have source file and line
242*12967Sgavin.maltby@oracle.com 	 * number and, if the producer was compiled with C99, function name.
243*12967Sgavin.maltby@oracle.com 	 */
244*12967Sgavin.maltby@oracle.com 	if (nvlist_lookup_string(attr, "__fmev_file", &str) == 0) {
245*12967Sgavin.maltby@oracle.com 		err += nvlist_add_string(site, FM_FMRI_SW_SITE_FILE, str);
246*12967Sgavin.maltby@oracle.com 		(void) nvlist_remove(attr, "__fmev_file", DATA_TYPE_STRING);
247*12967Sgavin.maltby@oracle.com 	}
248*12967Sgavin.maltby@oracle.com 
249*12967Sgavin.maltby@oracle.com 	if (nvlist_lookup_string(attr, "__fmev_func", &str) == 0) {
250*12967Sgavin.maltby@oracle.com 		err += nvlist_add_string(site, FM_FMRI_SW_SITE_FUNC, str);
251*12967Sgavin.maltby@oracle.com 		(void) nvlist_remove(attr, "__fmev_func", DATA_TYPE_STRING);
252*12967Sgavin.maltby@oracle.com 	}
253*12967Sgavin.maltby@oracle.com 
254*12967Sgavin.maltby@oracle.com 	if (nvlist_lookup_int64(attr, "__fmev_line", &i64) == 0) {
255*12967Sgavin.maltby@oracle.com 		err += nvlist_add_int64(site, FM_FMRI_SW_SITE_LINE, i64);
256*12967Sgavin.maltby@oracle.com 		(void) nvlist_remove(attr, "__fmev_line", DATA_TYPE_INT64);
257*12967Sgavin.maltby@oracle.com 	}
258*12967Sgavin.maltby@oracle.com 
259*12967Sgavin.maltby@oracle.com 	/*
260*12967Sgavin.maltby@oracle.com 	 * Build up 'context' nvlist.  We do not include contract id at
261*12967Sgavin.maltby@oracle.com 	 * this time.
262*12967Sgavin.maltby@oracle.com 	 */
263*12967Sgavin.maltby@oracle.com 
264*12967Sgavin.maltby@oracle.com 	err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_ORIGIN,
265*12967Sgavin.maltby@oracle.com 	    user ? "userland" : "kernel");
266*12967Sgavin.maltby@oracle.com 
267*12967Sgavin.maltby@oracle.com 	if (execname) {
268*12967Sgavin.maltby@oracle.com 		err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_EXECNAME,
269*12967Sgavin.maltby@oracle.com 		    execname);
270*12967Sgavin.maltby@oracle.com 		(void) nvlist_remove(attr, "__fmev_execname", DATA_TYPE_STRING);
271*12967Sgavin.maltby@oracle.com 	}
272*12967Sgavin.maltby@oracle.com 
273*12967Sgavin.maltby@oracle.com 	if (nvlist_lookup_int32(attr, "__fmev_pid", &i32) == 0) {
274*12967Sgavin.maltby@oracle.com 		err += nvlist_add_int32(ctxt, FM_FMRI_SW_CTXT_PID, i32);
275*12967Sgavin.maltby@oracle.com 		(void) nvlist_remove(attr, "__fmev_pid", DATA_TYPE_INT32);
276*12967Sgavin.maltby@oracle.com 	}
277*12967Sgavin.maltby@oracle.com 
278*12967Sgavin.maltby@oracle.com 	if (!isglobalzone)
279*12967Sgavin.maltby@oracle.com 		err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_ZONE, zonename);
280*12967Sgavin.maltby@oracle.com 
281*12967Sgavin.maltby@oracle.com 	/* Put it all together */
282*12967Sgavin.maltby@oracle.com 
283*12967Sgavin.maltby@oracle.com 	err += nvlist_add_uint8(dtcr, FM_VERSION, SW_SCHEME_VERSION0);
284*12967Sgavin.maltby@oracle.com 	err += nvlist_add_string(dtcr, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SW);
285*12967Sgavin.maltby@oracle.com 	err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_OBJ, obj);
286*12967Sgavin.maltby@oracle.com 	err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_SITE, site);
287*12967Sgavin.maltby@oracle.com 	err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_CTXT, ctxt);
288*12967Sgavin.maltby@oracle.com 
289*12967Sgavin.maltby@oracle.com done:
290*12967Sgavin.maltby@oracle.com 	if (obj != NULL)
291*12967Sgavin.maltby@oracle.com 		nvlist_free(obj);
292*12967Sgavin.maltby@oracle.com 	if (site != NULL)
293*12967Sgavin.maltby@oracle.com 		nvlist_free(site);
294*12967Sgavin.maltby@oracle.com 	if (ctxt != NULL)
295*12967Sgavin.maltby@oracle.com 		nvlist_free(ctxt);
296*12967Sgavin.maltby@oracle.com 
297*12967Sgavin.maltby@oracle.com 	if (err == 0) {
298*12967Sgavin.maltby@oracle.com 		return (dtcr);
299*12967Sgavin.maltby@oracle.com 	} else {
300*12967Sgavin.maltby@oracle.com 		nvlist_free(dtcr);
301*12967Sgavin.maltby@oracle.com 		return (NULL);
302*12967Sgavin.maltby@oracle.com 	}
303*12967Sgavin.maltby@oracle.com }
304*12967Sgavin.maltby@oracle.com 
305*12967Sgavin.maltby@oracle.com static int
class_ok(char * class)306*12967Sgavin.maltby@oracle.com class_ok(char *class)
307*12967Sgavin.maltby@oracle.com {
308*12967Sgavin.maltby@oracle.com 	static const char *approved[] = {
309*12967Sgavin.maltby@oracle.com 		FM_IREPORT_CLASS ".",
310*12967Sgavin.maltby@oracle.com 		FM_EREPORT_CLASS "."
311*12967Sgavin.maltby@oracle.com 	};
312*12967Sgavin.maltby@oracle.com 
313*12967Sgavin.maltby@oracle.com 	int i;
314*12967Sgavin.maltby@oracle.com 
315*12967Sgavin.maltby@oracle.com 	for (i = 0; i < sizeof (approved) / sizeof (approved[0]); i++) {
316*12967Sgavin.maltby@oracle.com 		if (strncmp(class, approved[i], strlen(approved[i])) == 0)
317*12967Sgavin.maltby@oracle.com 			return (1);
318*12967Sgavin.maltby@oracle.com 	}
319*12967Sgavin.maltby@oracle.com 
320*12967Sgavin.maltby@oracle.com 	return (0);
321*12967Sgavin.maltby@oracle.com }
322*12967Sgavin.maltby@oracle.com 
323*12967Sgavin.maltby@oracle.com static void
fmevt_postprocess(char * ruleset,nvlist_t * dtcr,nvlist_t * rawattr,struct fmevt_ppargs * eap)324*12967Sgavin.maltby@oracle.com fmevt_postprocess(char *ruleset, nvlist_t *dtcr, nvlist_t *rawattr,
325*12967Sgavin.maltby@oracle.com     struct fmevt_ppargs *eap)
326*12967Sgavin.maltby@oracle.com {
327*12967Sgavin.maltby@oracle.com 	uint_t expected = 0, processed = 0;
328*12967Sgavin.maltby@oracle.com 	char rs2burst[FMEV_MAX_RULESET_LEN + 1];
329*12967Sgavin.maltby@oracle.com 	char *class[FMEVT_FANOUT_MAX];
330*12967Sgavin.maltby@oracle.com 	nvlist_t *attr[FMEVT_FANOUT_MAX];
331*12967Sgavin.maltby@oracle.com 	fmevt_pp_func_t *dispf = NULL;
332*12967Sgavin.maltby@oracle.com 	char buf[FMEV_MAX_CLASS];
333*12967Sgavin.maltby@oracle.com 	char *ns, *subsys;
334*12967Sgavin.maltby@oracle.com 	int i, found = 0;
335*12967Sgavin.maltby@oracle.com 	uuid_t uu;
336*12967Sgavin.maltby@oracle.com 
337*12967Sgavin.maltby@oracle.com 	(void) strncpy(rs2burst, ruleset, sizeof (rs2burst));
338*12967Sgavin.maltby@oracle.com 	if (!fmevt_rs_burst(NULL, rs2burst, &ns, &subsys, B_FALSE)) {
339*12967Sgavin.maltby@oracle.com 		BUMPSTAT(pp_bad_ruleset);
340*12967Sgavin.maltby@oracle.com 		return;
341*12967Sgavin.maltby@oracle.com 	}
342*12967Sgavin.maltby@oracle.com 
343*12967Sgavin.maltby@oracle.com 	/*
344*12967Sgavin.maltby@oracle.com 	 * Lookup a matching rule in our table.
345*12967Sgavin.maltby@oracle.com 	 */
346*12967Sgavin.maltby@oracle.com 	for (i = 0; i < sizeof (rulelist) / sizeof (rulelist[0]); i++) {
347*12967Sgavin.maltby@oracle.com 		struct fmevt_rs *rsp = &rulelist[i];
348*12967Sgavin.maltby@oracle.com 
349*12967Sgavin.maltby@oracle.com 		if (*ns != '*' && *rsp->rs_namespace != '*' &&
350*12967Sgavin.maltby@oracle.com 		    strcmp(ns, rsp->rs_namespace) != 0)
351*12967Sgavin.maltby@oracle.com 			continue;
352*12967Sgavin.maltby@oracle.com 
353*12967Sgavin.maltby@oracle.com 		if (*subsys != '*' && *rsp->rs_subsys != '*' &&
354*12967Sgavin.maltby@oracle.com 		    strcmp(subsys, rsp->rs_subsys) != 0)
355*12967Sgavin.maltby@oracle.com 			continue;
356*12967Sgavin.maltby@oracle.com 
357*12967Sgavin.maltby@oracle.com 		dispf = rsp->rs_ppfunc;
358*12967Sgavin.maltby@oracle.com 		found = 1;
359*12967Sgavin.maltby@oracle.com 		break;
360*12967Sgavin.maltby@oracle.com 
361*12967Sgavin.maltby@oracle.com 	}
362*12967Sgavin.maltby@oracle.com 
363*12967Sgavin.maltby@oracle.com 	/*
364*12967Sgavin.maltby@oracle.com 	 * If a ruleset matches but specifies a NULL function then
365*12967Sgavin.maltby@oracle.com 	 * it's electing to drop the event.  If no rule was matched
366*12967Sgavin.maltby@oracle.com 	 * then default to unregistered processing.
367*12967Sgavin.maltby@oracle.com 	 */
368*12967Sgavin.maltby@oracle.com 	if (dispf == NULL) {
369*12967Sgavin.maltby@oracle.com 		if (found) {
370*12967Sgavin.maltby@oracle.com 			BUMPSTAT(pp_explicitdrop);
371*12967Sgavin.maltby@oracle.com 			return;
372*12967Sgavin.maltby@oracle.com 		} else {
373*12967Sgavin.maltby@oracle.com 			BUMPSTAT(pp_fallthrurule);
374*12967Sgavin.maltby@oracle.com 			dispf = fmevt_pp_unregistered;
375*12967Sgavin.maltby@oracle.com 		}
376*12967Sgavin.maltby@oracle.com 	}
377*12967Sgavin.maltby@oracle.com 
378*12967Sgavin.maltby@oracle.com 	/*
379*12967Sgavin.maltby@oracle.com 	 * Clear the arrays in which class strings and attribute
380*12967Sgavin.maltby@oracle.com 	 * nvlists can be returned.  Pass a pointer to our stack buffer
381*12967Sgavin.maltby@oracle.com 	 * that the callee can use for the first event class (for others
382*12967Sgavin.maltby@oracle.com 	 * it must fmd_hdl_alloc and we'll free below).  We will free
383*12967Sgavin.maltby@oracle.com 	 * and nvlists that are returned.
384*12967Sgavin.maltby@oracle.com 	 */
385*12967Sgavin.maltby@oracle.com 	bzero(class, sizeof (class));
386*12967Sgavin.maltby@oracle.com 	bzero(attr, sizeof (attr));
387*12967Sgavin.maltby@oracle.com 	class[0] = buf;
388*12967Sgavin.maltby@oracle.com 
389*12967Sgavin.maltby@oracle.com 	/*
390*12967Sgavin.maltby@oracle.com 	 * Generate an event UUID which will be used for the first
391*12967Sgavin.maltby@oracle.com 	 * event generated by post-processing; if post-processing
392*12967Sgavin.maltby@oracle.com 	 * fans out into more than one event the additional events
393*12967Sgavin.maltby@oracle.com 	 * can reference this uuid (but we don't generate their
394*12967Sgavin.maltby@oracle.com 	 * UUIDs until later).
395*12967Sgavin.maltby@oracle.com 	 */
396*12967Sgavin.maltby@oracle.com 	uuid_generate(uu);
397*12967Sgavin.maltby@oracle.com 	uuid_unparse(uu, eap->pp_uuidstr);
398*12967Sgavin.maltby@oracle.com 
399*12967Sgavin.maltby@oracle.com 	/*
400*12967Sgavin.maltby@oracle.com 	 * Call selected post-processing function.  See block comment
401*12967Sgavin.maltby@oracle.com 	 * in fmevt.h for a description of this process.
402*12967Sgavin.maltby@oracle.com 	 */
403*12967Sgavin.maltby@oracle.com 	expected = (*dispf)(class, attr, ruleset,
404*12967Sgavin.maltby@oracle.com 	    (const nvlist_t *)dtcr, rawattr,
405*12967Sgavin.maltby@oracle.com 	    (const struct fmevt_ppargs *)eap);
406*12967Sgavin.maltby@oracle.com 
407*12967Sgavin.maltby@oracle.com 	if (expected > FMEVT_FANOUT_MAX) {
408*12967Sgavin.maltby@oracle.com 		BUMPSTAT(pp_fanoutmax);
409*12967Sgavin.maltby@oracle.com 		return;	/* without freeing class and nvl - could leak */
410*12967Sgavin.maltby@oracle.com 	} else if (expected == 0) {
411*12967Sgavin.maltby@oracle.com 		BUMPSTAT(pp_intldrop);
412*12967Sgavin.maltby@oracle.com 		return;
413*12967Sgavin.maltby@oracle.com 	}
414*12967Sgavin.maltby@oracle.com 
415*12967Sgavin.maltby@oracle.com 	/*
416*12967Sgavin.maltby@oracle.com 	 * Post as many events as the callback completed.
417*12967Sgavin.maltby@oracle.com 	 */
418*12967Sgavin.maltby@oracle.com 	for (i = 0; i < FMEVT_FANOUT_MAX; i++) {
419*12967Sgavin.maltby@oracle.com 		char uuidstr[36 + 1];
420*12967Sgavin.maltby@oracle.com 		char *uuidstrp;
421*12967Sgavin.maltby@oracle.com 		nvlist_t *nvl;
422*12967Sgavin.maltby@oracle.com 		int err = 0;
423*12967Sgavin.maltby@oracle.com 
424*12967Sgavin.maltby@oracle.com 		if (class[i] == NULL)
425*12967Sgavin.maltby@oracle.com 			continue;
426*12967Sgavin.maltby@oracle.com 
427*12967Sgavin.maltby@oracle.com 		if (!class_ok(class[i])) {
428*12967Sgavin.maltby@oracle.com 			BUMPSTAT(pp_badclass);
429*12967Sgavin.maltby@oracle.com 			continue;
430*12967Sgavin.maltby@oracle.com 		}
431*12967Sgavin.maltby@oracle.com 
432*12967Sgavin.maltby@oracle.com 		if (processed++ == 0) {
433*12967Sgavin.maltby@oracle.com 			uuidstrp = eap->pp_uuidstr;
434*12967Sgavin.maltby@oracle.com 		} else {
435*12967Sgavin.maltby@oracle.com 			uuid_generate(uu);
436*12967Sgavin.maltby@oracle.com 			uuid_unparse(uu, uuidstr);
437*12967Sgavin.maltby@oracle.com 			uuidstrp = uuidstr;
438*12967Sgavin.maltby@oracle.com 		}
439*12967Sgavin.maltby@oracle.com 
440*12967Sgavin.maltby@oracle.com 		if ((nvl = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP)) == NULL) {
441*12967Sgavin.maltby@oracle.com 			BUMPSTAT(pp_nvlallocfail);
442*12967Sgavin.maltby@oracle.com 			continue;
443*12967Sgavin.maltby@oracle.com 		}
444*12967Sgavin.maltby@oracle.com 
445*12967Sgavin.maltby@oracle.com 		err += nvlist_add_uint8(nvl, FM_VERSION, 0);
446*12967Sgavin.maltby@oracle.com 		err += nvlist_add_string(nvl, FM_CLASS, (const char *)class[i]);
447*12967Sgavin.maltby@oracle.com 		err += nvlist_add_string(nvl, FM_IREPORT_UUID, uuidstrp);
448*12967Sgavin.maltby@oracle.com 		err += nvlist_add_nvlist(nvl, FM_IREPORT_DETECTOR, dtcr);
449*12967Sgavin.maltby@oracle.com 		err += nvlist_add_string(nvl, FM_IREPORT_PRIORITY,
450*12967Sgavin.maltby@oracle.com 		    fmev_pri_string(eap->pp_pri) ?
451*12967Sgavin.maltby@oracle.com 		    fmev_pri_string(eap->pp_pri) : "?");
452*12967Sgavin.maltby@oracle.com 
453*12967Sgavin.maltby@oracle.com 		if (attr[i] != NULL)
454*12967Sgavin.maltby@oracle.com 			err += nvlist_add_nvlist(nvl, FM_IREPORT_ATTRIBUTES,
455*12967Sgavin.maltby@oracle.com 			    attr[i]);
456*12967Sgavin.maltby@oracle.com 
457*12967Sgavin.maltby@oracle.com 		/*
458*12967Sgavin.maltby@oracle.com 		 * If we post the event into fmd_xport_post then the
459*12967Sgavin.maltby@oracle.com 		 * transport code is responsible for freeing the nvl we
460*12967Sgavin.maltby@oracle.com 		 * posted.
461*12967Sgavin.maltby@oracle.com 		 */
462*12967Sgavin.maltby@oracle.com 		if (err == 0) {
463*12967Sgavin.maltby@oracle.com 			fmd_xprt_post(fmevt_hdl, fmevt_xprt, nvl,
464*12967Sgavin.maltby@oracle.com 			    eap->pp_hrt);
465*12967Sgavin.maltby@oracle.com 		} else {
466*12967Sgavin.maltby@oracle.com 			BUMPSTAT(pp_nvlbuildfail);
467*12967Sgavin.maltby@oracle.com 			nvlist_free(nvl);
468*12967Sgavin.maltby@oracle.com 		}
469*12967Sgavin.maltby@oracle.com 	}
470*12967Sgavin.maltby@oracle.com 
471*12967Sgavin.maltby@oracle.com 	if (processed != expected)
472*12967Sgavin.maltby@oracle.com 		BUMPSTAT(pp_badreturn);
473*12967Sgavin.maltby@oracle.com 
474*12967Sgavin.maltby@oracle.com 	for (i = 0; i < FMEVT_FANOUT_MAX; i++) {
475*12967Sgavin.maltby@oracle.com 		/*
476*12967Sgavin.maltby@oracle.com 		 * We provided storage for class[0] but any
477*12967Sgavin.maltby@oracle.com 		 * additional events have allocated a string.
478*12967Sgavin.maltby@oracle.com 		 */
479*12967Sgavin.maltby@oracle.com 		if (i > 0 && class[i] != NULL)
480*12967Sgavin.maltby@oracle.com 			fmd_hdl_strfree(fmevt_hdl, class[i]);
481*12967Sgavin.maltby@oracle.com 
482*12967Sgavin.maltby@oracle.com 		/*
483*12967Sgavin.maltby@oracle.com 		 * Free all attribute lists passed in if they are not
484*12967Sgavin.maltby@oracle.com 		 * just a pointer to the raw attributes
485*12967Sgavin.maltby@oracle.com 		 */
486*12967Sgavin.maltby@oracle.com 		if (attr[i] != NULL && attr[i] != rawattr)
487*12967Sgavin.maltby@oracle.com 			nvlist_free(attr[i]);
488*12967Sgavin.maltby@oracle.com 	}
489*12967Sgavin.maltby@oracle.com }
490*12967Sgavin.maltby@oracle.com 
491*12967Sgavin.maltby@oracle.com static int
fmevt_cb(sysevent_t * sep,void * arg)492*12967Sgavin.maltby@oracle.com fmevt_cb(sysevent_t *sep, void *arg)
493*12967Sgavin.maltby@oracle.com {
494*12967Sgavin.maltby@oracle.com 	char *ruleset = NULL, *rawclass, *rawsubclass;
495*12967Sgavin.maltby@oracle.com 	uint32_t cbarg = (uint32_t)arg;
496*12967Sgavin.maltby@oracle.com 	nvlist_t *rawattr = NULL;
497*12967Sgavin.maltby@oracle.com 	struct fmevt_ppargs ea;
498*12967Sgavin.maltby@oracle.com 	nvlist_t *dtcr;
499*12967Sgavin.maltby@oracle.com 	int user, priv;
500*12967Sgavin.maltby@oracle.com 	fmev_pri_t pri;
501*12967Sgavin.maltby@oracle.com 
502*12967Sgavin.maltby@oracle.com 	BUMPSTAT(raw_callbacks);
503*12967Sgavin.maltby@oracle.com 
504*12967Sgavin.maltby@oracle.com 	if (cbarg & ~CBF_ALL)
505*12967Sgavin.maltby@oracle.com 		fmd_hdl_abort(fmevt_hdl, "event receipt callback with "
506*12967Sgavin.maltby@oracle.com 		    "invalid flags\n");
507*12967Sgavin.maltby@oracle.com 
508*12967Sgavin.maltby@oracle.com 	user = (cbarg & CBF_USER) != 0;
509*12967Sgavin.maltby@oracle.com 	priv = (cbarg & CBF_PRIV) != 0;
510*12967Sgavin.maltby@oracle.com 	pri = (cbarg & CBF_HV ? FMEV_HIPRI : FMEV_LOPRI);
511*12967Sgavin.maltby@oracle.com 
512*12967Sgavin.maltby@oracle.com 	(void) pthread_mutex_lock(&fmevt_lock);
513*12967Sgavin.maltby@oracle.com 
514*12967Sgavin.maltby@oracle.com 	if (fmevt_exiting) {
515*12967Sgavin.maltby@oracle.com 		while (fmevt_xprt_refcnt > 0)
516*12967Sgavin.maltby@oracle.com 			(void) pthread_cond_wait(&fmevt_cv, &fmevt_lock);
517*12967Sgavin.maltby@oracle.com 		(void) pthread_mutex_unlock(&fmevt_lock);
518*12967Sgavin.maltby@oracle.com 		return (0);	/* discard event */
519*12967Sgavin.maltby@oracle.com 	}
520*12967Sgavin.maltby@oracle.com 
521*12967Sgavin.maltby@oracle.com 	fmevt_xprt_refcnt++;
522*12967Sgavin.maltby@oracle.com 	(void) pthread_mutex_unlock(&fmevt_lock);
523*12967Sgavin.maltby@oracle.com 
524*12967Sgavin.maltby@oracle.com 	ruleset = sysevent_get_vendor_name(sep);	/* must free */
525*12967Sgavin.maltby@oracle.com 	rawclass = sysevent_get_class_name(sep);	/* valid with sep */
526*12967Sgavin.maltby@oracle.com 	rawsubclass = sysevent_get_subclass_name(sep);	/* valid with sep */
527*12967Sgavin.maltby@oracle.com 
528*12967Sgavin.maltby@oracle.com 	if (sysevent_get_attr_list(sep, &rawattr) != 0) {
529*12967Sgavin.maltby@oracle.com 		BUMPSTAT(raw_noattrlist);
530*12967Sgavin.maltby@oracle.com 		goto done;
531*12967Sgavin.maltby@oracle.com 	}
532*12967Sgavin.maltby@oracle.com 
533*12967Sgavin.maltby@oracle.com 	if ((dtcr = fmevt_detector(rawattr, ruleset, user, priv,
534*12967Sgavin.maltby@oracle.com 	    pri)) == NULL) {
535*12967Sgavin.maltby@oracle.com 		BUMPSTAT(raw_nodetector);
536*12967Sgavin.maltby@oracle.com 		goto done;
537*12967Sgavin.maltby@oracle.com 	}
538*12967Sgavin.maltby@oracle.com 
539*12967Sgavin.maltby@oracle.com 	ea.pp_rawclass = rawclass;
540*12967Sgavin.maltby@oracle.com 	ea.pp_rawsubclass = rawsubclass;
541*12967Sgavin.maltby@oracle.com 	sysevent_get_time(sep, &ea.pp_hrt);
542*12967Sgavin.maltby@oracle.com 	ea.pp_user = user;
543*12967Sgavin.maltby@oracle.com 	ea.pp_priv = priv;
544*12967Sgavin.maltby@oracle.com 	ea.pp_pri = pri;
545*12967Sgavin.maltby@oracle.com 
546*12967Sgavin.maltby@oracle.com 	fmevt_postprocess(ruleset, dtcr, rawattr, &ea);
547*12967Sgavin.maltby@oracle.com 	nvlist_free(dtcr);
548*12967Sgavin.maltby@oracle.com done:
549*12967Sgavin.maltby@oracle.com 	(void) pthread_mutex_lock(&fmevt_lock);
550*12967Sgavin.maltby@oracle.com 
551*12967Sgavin.maltby@oracle.com 	if (--fmevt_xprt_refcnt == 0 && fmevt_exiting)
552*12967Sgavin.maltby@oracle.com 		(void) pthread_cond_broadcast(&fmevt_cv);
553*12967Sgavin.maltby@oracle.com 
554*12967Sgavin.maltby@oracle.com 	(void) pthread_mutex_unlock(&fmevt_lock);
555*12967Sgavin.maltby@oracle.com 
556*12967Sgavin.maltby@oracle.com 	if (ruleset)
557*12967Sgavin.maltby@oracle.com 		free(ruleset);
558*12967Sgavin.maltby@oracle.com 
559*12967Sgavin.maltby@oracle.com 	if (rawattr)
560*12967Sgavin.maltby@oracle.com 		nvlist_free(rawattr);
561*12967Sgavin.maltby@oracle.com 
562*12967Sgavin.maltby@oracle.com 	return (0);	/* in all cases consider the event delivered */
563*12967Sgavin.maltby@oracle.com }
564*12967Sgavin.maltby@oracle.com 
565*12967Sgavin.maltby@oracle.com void
fmevt_init_inbound(fmd_hdl_t * hdl)566*12967Sgavin.maltby@oracle.com fmevt_init_inbound(fmd_hdl_t *hdl)
567*12967Sgavin.maltby@oracle.com {
568*12967Sgavin.maltby@oracle.com 	char *sidpfx;
569*12967Sgavin.maltby@oracle.com 	zoneid_t zoneid;
570*12967Sgavin.maltby@oracle.com 	int i;
571*12967Sgavin.maltby@oracle.com 
572*12967Sgavin.maltby@oracle.com 	if (!fmevt_rs_init(hdl))
573*12967Sgavin.maltby@oracle.com 		fmd_hdl_abort(hdl, "error in fmevt_rs_init\n");
574*12967Sgavin.maltby@oracle.com 
575*12967Sgavin.maltby@oracle.com 	(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (inbound_stats) /
576*12967Sgavin.maltby@oracle.com 	    sizeof (fmd_stat_t), (fmd_stat_t *)&inbound_stats);
577*12967Sgavin.maltby@oracle.com 
578*12967Sgavin.maltby@oracle.com 	zoneid = getzoneid();
579*12967Sgavin.maltby@oracle.com 	isglobalzone = (zoneid == GLOBAL_ZONEID);
580*12967Sgavin.maltby@oracle.com 	if (getzonenamebyid(zoneid, zonename, sizeof (zonename)) == -1)
581*12967Sgavin.maltby@oracle.com 		fmd_hdl_abort(hdl, "getzonenamebyid failed");
582*12967Sgavin.maltby@oracle.com 
583*12967Sgavin.maltby@oracle.com 	if ((subattr = sysevent_subattr_alloc()) == NULL)
584*12967Sgavin.maltby@oracle.com 		fmd_hdl_abort(hdl, "failed to allocate subscription "
585*12967Sgavin.maltby@oracle.com 		    "attributes: %s");
586*12967Sgavin.maltby@oracle.com 
587*12967Sgavin.maltby@oracle.com 	sysevent_subattr_thrcreate(subattr, fmd_doorthr_create, NULL);
588*12967Sgavin.maltby@oracle.com 	sysevent_subattr_thrsetup(subattr, fmd_doorthr_setup, NULL);
589*12967Sgavin.maltby@oracle.com 
590*12967Sgavin.maltby@oracle.com 	sidpfx = fmd_prop_get_string(hdl, "sidprefix");
591*12967Sgavin.maltby@oracle.com 	fmevt_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL);
592*12967Sgavin.maltby@oracle.com 
593*12967Sgavin.maltby@oracle.com 	for (i = 0; i < sizeof (chaninfo) / sizeof (chaninfo[0]); i++) {
594*12967Sgavin.maltby@oracle.com 		struct fmevt_chaninfo *cip = &chaninfo[i];
595*12967Sgavin.maltby@oracle.com 		char *channel = fmd_prop_get_string(hdl, cip->ci_propname);
596*12967Sgavin.maltby@oracle.com 		int err;
597*12967Sgavin.maltby@oracle.com 
598*12967Sgavin.maltby@oracle.com 		if (sysevent_evc_bind(channel, &cip->ci_binding,
599*12967Sgavin.maltby@oracle.com 		    EVCH_CREAT | EVCH_HOLD_PEND_INDEF) != 0)
600*12967Sgavin.maltby@oracle.com 			fmd_hdl_abort(hdl, "failed to bind GPEC channel for "
601*12967Sgavin.maltby@oracle.com 			    "channel %s", channel);
602*12967Sgavin.maltby@oracle.com 
603*12967Sgavin.maltby@oracle.com 		(void) snprintf(cip->ci_sid, sizeof (cip->ci_sid),
604*12967Sgavin.maltby@oracle.com 		    "%s_%c%c%c", sidpfx,
605*12967Sgavin.maltby@oracle.com 		    cip->ci_cbarg & CBF_USER ? 'u' : 'k',
606*12967Sgavin.maltby@oracle.com 		    cip->ci_cbarg & CBF_PRIV ? 'p' : 'n',
607*12967Sgavin.maltby@oracle.com 		    cip->ci_cbarg & CBF_HV ? 'h' : 'l');
608*12967Sgavin.maltby@oracle.com 
609*12967Sgavin.maltby@oracle.com 		err = sysevent_evc_xsubscribe(cip->ci_binding, cip->ci_sid,
610*12967Sgavin.maltby@oracle.com 		    EC_ALL, fmevt_cb, (void *)cip->ci_cbarg,
611*12967Sgavin.maltby@oracle.com 		    cip->ci_sflags, subattr);
612*12967Sgavin.maltby@oracle.com 
613*12967Sgavin.maltby@oracle.com 		if (err == EEXIST)
614*12967Sgavin.maltby@oracle.com 			fmd_hdl_abort(hdl, "another fmd is active on "
615*12967Sgavin.maltby@oracle.com 			    "channel %s\n", channel);
616*12967Sgavin.maltby@oracle.com 		else if (err != 0)
617*12967Sgavin.maltby@oracle.com 			fmd_hdl_abort(hdl, "failed to subscribe to channel %s",
618*12967Sgavin.maltby@oracle.com 			    channel);
619*12967Sgavin.maltby@oracle.com 
620*12967Sgavin.maltby@oracle.com 		fmd_prop_free_string(hdl, channel);
621*12967Sgavin.maltby@oracle.com 	}
622*12967Sgavin.maltby@oracle.com 
623*12967Sgavin.maltby@oracle.com 	fmd_prop_free_string(hdl, sidpfx);
624*12967Sgavin.maltby@oracle.com }
625*12967Sgavin.maltby@oracle.com 
626*12967Sgavin.maltby@oracle.com void
fmevt_fini_inbound(fmd_hdl_t * hdl)627*12967Sgavin.maltby@oracle.com fmevt_fini_inbound(fmd_hdl_t *hdl)
628*12967Sgavin.maltby@oracle.com {
629*12967Sgavin.maltby@oracle.com 	int i;
630*12967Sgavin.maltby@oracle.com 
631*12967Sgavin.maltby@oracle.com 	for (i = 0; i < sizeof (chaninfo) / sizeof (chaninfo[0]); i++) {
632*12967Sgavin.maltby@oracle.com 		struct fmevt_chaninfo *cip = &chaninfo[i];
633*12967Sgavin.maltby@oracle.com 
634*12967Sgavin.maltby@oracle.com 		if (cip->ci_binding) {
635*12967Sgavin.maltby@oracle.com 			(void) sysevent_evc_unsubscribe(cip->ci_binding,
636*12967Sgavin.maltby@oracle.com 			    cip->ci_sid);
637*12967Sgavin.maltby@oracle.com 			(void) sysevent_evc_unbind(cip->ci_binding);
638*12967Sgavin.maltby@oracle.com 			cip->ci_binding = NULL;
639*12967Sgavin.maltby@oracle.com 		}
640*12967Sgavin.maltby@oracle.com 	}
641*12967Sgavin.maltby@oracle.com 
642*12967Sgavin.maltby@oracle.com 	if (subattr) {
643*12967Sgavin.maltby@oracle.com 		sysevent_subattr_free(subattr);
644*12967Sgavin.maltby@oracle.com 		subattr = NULL;
645*12967Sgavin.maltby@oracle.com 	}
646*12967Sgavin.maltby@oracle.com 
647*12967Sgavin.maltby@oracle.com 	if (fmevt_xprt) {
648*12967Sgavin.maltby@oracle.com 		/* drain before destruction */
649*12967Sgavin.maltby@oracle.com 		(void) pthread_mutex_lock(&fmevt_lock);
650*12967Sgavin.maltby@oracle.com 		fmevt_exiting = 1;
651*12967Sgavin.maltby@oracle.com 		while (fmevt_xprt_refcnt > 0)
652*12967Sgavin.maltby@oracle.com 			(void) pthread_cond_wait(&fmevt_cv, &fmevt_lock);
653*12967Sgavin.maltby@oracle.com 		(void) pthread_mutex_unlock(&fmevt_lock);
654*12967Sgavin.maltby@oracle.com 
655*12967Sgavin.maltby@oracle.com 		fmd_xprt_close(hdl, fmevt_xprt);
656*12967Sgavin.maltby@oracle.com 	}
657*12967Sgavin.maltby@oracle.com 
658*12967Sgavin.maltby@oracle.com }
659