xref: /onnv-gate/usr/src/lib/fm/libfmevent/common/fmev_publish.c (revision 12967:ab9ae749152f)
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  * Simple-minded raw event publication from user context.  See extensive
28*12967Sgavin.maltby@oracle.com  * comments in libfmevent.h.  These interfaces remain Project Private -
29*12967Sgavin.maltby@oracle.com  * they have to evolve before rollout to Public levels.
30*12967Sgavin.maltby@oracle.com  *
31*12967Sgavin.maltby@oracle.com  * Events are dispatched synchronously using the GPEC sysevent mechanism.
32*12967Sgavin.maltby@oracle.com  * The caller context must therefore be one in which a sysevent_evc_publish
33*12967Sgavin.maltby@oracle.com  * (and possibly sysevent_evc_bind if not already bound) is safe.  We will
34*12967Sgavin.maltby@oracle.com  * also allocate and manipulate nvlists.
35*12967Sgavin.maltby@oracle.com  *
36*12967Sgavin.maltby@oracle.com  * Since we use GPEC, which has no least privilege awareness, these interfaces
37*12967Sgavin.maltby@oracle.com  * will only work for would-be producers running as root.
38*12967Sgavin.maltby@oracle.com  *
39*12967Sgavin.maltby@oracle.com  * There is no event rate throttling applied, so we rely on producers
40*12967Sgavin.maltby@oracle.com  * to throttle themselves.  A future refinement should apply mandatory
41*12967Sgavin.maltby@oracle.com  * but tuneable throttling on a per-producer basis.  In this first version
42*12967Sgavin.maltby@oracle.com  * the only throttle is the publication event queue depth - we'll drop
43*12967Sgavin.maltby@oracle.com  * events when the queue is full.
44*12967Sgavin.maltby@oracle.com  *
45*12967Sgavin.maltby@oracle.com  * We can publish over four channels, for privileged/non-privileged and
46*12967Sgavin.maltby@oracle.com  * high/low priority.  Since only privileged producers will work now
47*12967Sgavin.maltby@oracle.com  * (see above) we hardcode priv == B_TRUE and so only two channels are
48*12967Sgavin.maltby@oracle.com  * actually used, separating higher and lower value streams from privileged
49*12967Sgavin.maltby@oracle.com  * producers.
50*12967Sgavin.maltby@oracle.com  */
51*12967Sgavin.maltby@oracle.com 
52*12967Sgavin.maltby@oracle.com #include <stdarg.h>
53*12967Sgavin.maltby@oracle.com #include <unistd.h>
54*12967Sgavin.maltby@oracle.com #include <stdlib.h>
55*12967Sgavin.maltby@oracle.com #include <atomic.h>
56*12967Sgavin.maltby@oracle.com #include <errno.h>
57*12967Sgavin.maltby@oracle.com #include <pthread.h>
58*12967Sgavin.maltby@oracle.com #include <strings.h>
59*12967Sgavin.maltby@oracle.com 
60*12967Sgavin.maltby@oracle.com #include "fmev_impl.h"
61*12967Sgavin.maltby@oracle.com 
62*12967Sgavin.maltby@oracle.com static struct {
63*12967Sgavin.maltby@oracle.com 	const char *name;		/* channel name */
64*12967Sgavin.maltby@oracle.com 	evchan_t *binding;		/* GPEC binding, once bound */
65*12967Sgavin.maltby@oracle.com 	const uint32_t flags;		/* flags to use in binding */
66*12967Sgavin.maltby@oracle.com } chaninfo[] = {
67*12967Sgavin.maltby@oracle.com 	{ FMEV_CHAN_USER_NOPRIV_LV, NULL, 0 },
68*12967Sgavin.maltby@oracle.com 	{ FMEV_CHAN_USER_NOPRIV_HV, NULL, 0 },
69*12967Sgavin.maltby@oracle.com 	{ FMEV_CHAN_USER_PRIV_LV, NULL, EVCH_HOLD_PEND_INDEF },
70*12967Sgavin.maltby@oracle.com 	{ FMEV_CHAN_USER_PRIV_HV, NULL, EVCH_HOLD_PEND_INDEF}
71*12967Sgavin.maltby@oracle.com };
72*12967Sgavin.maltby@oracle.com 
73*12967Sgavin.maltby@oracle.com #define	CHANIDX(priv, pri) (2 * ((priv) != 0) + (pri == FMEV_HIPRI))
74*12967Sgavin.maltby@oracle.com 
75*12967Sgavin.maltby@oracle.com #define	CHAN_NAME(priv, pri) (chaninfo[CHANIDX(priv, pri)].name)
76*12967Sgavin.maltby@oracle.com #define	CHAN_BINDING(priv, pri) (chaninfo[CHANIDX(priv, pri)].binding)
77*12967Sgavin.maltby@oracle.com #define	CHAN_FLAGS(priv, pri) (chaninfo[CHANIDX(priv, pri)].flags)
78*12967Sgavin.maltby@oracle.com 
79*12967Sgavin.maltby@oracle.com /*
80*12967Sgavin.maltby@oracle.com  * Called after fork in the new child.  We clear the cached event
81*12967Sgavin.maltby@oracle.com  * channel bindings which are only valid in the process that created
82*12967Sgavin.maltby@oracle.com  * them.
83*12967Sgavin.maltby@oracle.com  */
84*12967Sgavin.maltby@oracle.com static void
clear_bindings(void)85*12967Sgavin.maltby@oracle.com clear_bindings(void)
86*12967Sgavin.maltby@oracle.com {
87*12967Sgavin.maltby@oracle.com 	int i;
88*12967Sgavin.maltby@oracle.com 
89*12967Sgavin.maltby@oracle.com 	for (i = 0; i < sizeof (chaninfo) / sizeof chaninfo[0]; i++)
90*12967Sgavin.maltby@oracle.com 		chaninfo[i].binding = NULL;
91*12967Sgavin.maltby@oracle.com }
92*12967Sgavin.maltby@oracle.com 
93*12967Sgavin.maltby@oracle.com #pragma init(_fmev_publish_init)
94*12967Sgavin.maltby@oracle.com 
95*12967Sgavin.maltby@oracle.com static void
_fmev_publish_init(void)96*12967Sgavin.maltby@oracle.com _fmev_publish_init(void)
97*12967Sgavin.maltby@oracle.com {
98*12967Sgavin.maltby@oracle.com 	(void) pthread_atfork(NULL, NULL, clear_bindings);
99*12967Sgavin.maltby@oracle.com }
100*12967Sgavin.maltby@oracle.com 
101*12967Sgavin.maltby@oracle.com static evchan_t *
bind_channel(boolean_t priv,fmev_pri_t pri)102*12967Sgavin.maltby@oracle.com bind_channel(boolean_t priv, fmev_pri_t pri)
103*12967Sgavin.maltby@oracle.com {
104*12967Sgavin.maltby@oracle.com 	evchan_t **evcpp = &CHAN_BINDING(priv, pri);
105*12967Sgavin.maltby@oracle.com 	evchan_t *evc;
106*12967Sgavin.maltby@oracle.com 
107*12967Sgavin.maltby@oracle.com 	if (*evcpp != NULL)
108*12967Sgavin.maltby@oracle.com 		return (*evcpp);
109*12967Sgavin.maltby@oracle.com 
110*12967Sgavin.maltby@oracle.com 	if (sysevent_evc_bind(CHAN_NAME(priv, pri), &evc,
111*12967Sgavin.maltby@oracle.com 	    EVCH_CREAT | CHAN_FLAGS(priv, pri)) != 0)
112*12967Sgavin.maltby@oracle.com 		return (NULL);
113*12967Sgavin.maltby@oracle.com 
114*12967Sgavin.maltby@oracle.com 	if (atomic_cas_ptr(evcpp, NULL, evc) != NULL)
115*12967Sgavin.maltby@oracle.com 		(void) sysevent_evc_unbind(evc);
116*12967Sgavin.maltby@oracle.com 
117*12967Sgavin.maltby@oracle.com 	return (*evcpp);
118*12967Sgavin.maltby@oracle.com }
119*12967Sgavin.maltby@oracle.com 
120*12967Sgavin.maltby@oracle.com static fmev_err_t
vrfy_ruleset(const char * ruleset)121*12967Sgavin.maltby@oracle.com vrfy_ruleset(const char *ruleset)
122*12967Sgavin.maltby@oracle.com {
123*12967Sgavin.maltby@oracle.com 	if (ruleset != NULL &&
124*12967Sgavin.maltby@oracle.com 	    strnlen(ruleset, FMEV_MAX_RULESET_LEN) == FMEV_MAX_RULESET_LEN)
125*12967Sgavin.maltby@oracle.com 		return (FMEVERR_STRING2BIG);
126*12967Sgavin.maltby@oracle.com 
127*12967Sgavin.maltby@oracle.com 	return (FMEV_OK);
128*12967Sgavin.maltby@oracle.com 
129*12967Sgavin.maltby@oracle.com }
130*12967Sgavin.maltby@oracle.com 
131*12967Sgavin.maltby@oracle.com static fmev_err_t
vrfy_class(const char * class)132*12967Sgavin.maltby@oracle.com vrfy_class(const char *class)
133*12967Sgavin.maltby@oracle.com {
134*12967Sgavin.maltby@oracle.com 	if (class == NULL || *class == '\0')
135*12967Sgavin.maltby@oracle.com 		return (FMEVERR_API);
136*12967Sgavin.maltby@oracle.com 
137*12967Sgavin.maltby@oracle.com 	if (strnlen(class, FMEV_PUB_MAXCLASSLEN) == FMEV_PUB_MAXCLASSLEN)
138*12967Sgavin.maltby@oracle.com 		return (FMEVERR_STRING2BIG);
139*12967Sgavin.maltby@oracle.com 
140*12967Sgavin.maltby@oracle.com 	return (FMEV_OK);
141*12967Sgavin.maltby@oracle.com }
142*12967Sgavin.maltby@oracle.com 
143*12967Sgavin.maltby@oracle.com static fmev_err_t
vrfy_subclass(const char * subclass)144*12967Sgavin.maltby@oracle.com vrfy_subclass(const char *subclass)
145*12967Sgavin.maltby@oracle.com {
146*12967Sgavin.maltby@oracle.com 	if (subclass == NULL || *subclass == '\0')
147*12967Sgavin.maltby@oracle.com 		return (FMEVERR_API);
148*12967Sgavin.maltby@oracle.com 
149*12967Sgavin.maltby@oracle.com 	if (strnlen(subclass, FMEV_PUB_MAXSUBCLASSLEN) ==
150*12967Sgavin.maltby@oracle.com 	    FMEV_PUB_MAXSUBCLASSLEN)
151*12967Sgavin.maltby@oracle.com 		return (FMEVERR_STRING2BIG);
152*12967Sgavin.maltby@oracle.com 
153*12967Sgavin.maltby@oracle.com 	return (FMEV_OK);
154*12967Sgavin.maltby@oracle.com }
155*12967Sgavin.maltby@oracle.com 
156*12967Sgavin.maltby@oracle.com static fmev_err_t
vrfy_pri(fmev_pri_t pri)157*12967Sgavin.maltby@oracle.com vrfy_pri(fmev_pri_t pri)
158*12967Sgavin.maltby@oracle.com {
159*12967Sgavin.maltby@oracle.com 	return (pri == FMEV_LOPRI || pri == FMEV_HIPRI ?
160*12967Sgavin.maltby@oracle.com 	    FMEV_OK : FMEVERR_API);
161*12967Sgavin.maltby@oracle.com }
162*12967Sgavin.maltby@oracle.com 
163*12967Sgavin.maltby@oracle.com const char *
fmev_pri_string(fmev_pri_t pri)164*12967Sgavin.maltby@oracle.com fmev_pri_string(fmev_pri_t pri)
165*12967Sgavin.maltby@oracle.com {
166*12967Sgavin.maltby@oracle.com 	static const char *pristr[] = { "low", "high" };
167*12967Sgavin.maltby@oracle.com 
168*12967Sgavin.maltby@oracle.com 	if (vrfy_pri(pri) != FMEV_OK)
169*12967Sgavin.maltby@oracle.com 		return (NULL);
170*12967Sgavin.maltby@oracle.com 
171*12967Sgavin.maltby@oracle.com 	return (pristr[pri - FMEV_LOPRI]);
172*12967Sgavin.maltby@oracle.com }
173*12967Sgavin.maltby@oracle.com 
174*12967Sgavin.maltby@oracle.com static fmev_err_t
vrfy(const char ** rulesetp,const char ** classp,const char ** subclassp,fmev_pri_t * prip)175*12967Sgavin.maltby@oracle.com vrfy(const char **rulesetp, const char **classp, const char **subclassp,
176*12967Sgavin.maltby@oracle.com     fmev_pri_t *prip)
177*12967Sgavin.maltby@oracle.com {
178*12967Sgavin.maltby@oracle.com 	fmev_err_t rc = FMEV_OK;
179*12967Sgavin.maltby@oracle.com 
180*12967Sgavin.maltby@oracle.com 	if (rulesetp && (rc = vrfy_ruleset(*rulesetp)) != FMEV_OK)
181*12967Sgavin.maltby@oracle.com 		return (rc);
182*12967Sgavin.maltby@oracle.com 
183*12967Sgavin.maltby@oracle.com 	if (classp && (rc = vrfy_class(*classp)) != FMEV_OK ||
184*12967Sgavin.maltby@oracle.com 	    subclassp && (rc = vrfy_subclass(*subclassp)) != FMEV_OK ||
185*12967Sgavin.maltby@oracle.com 	    prip && (rc = vrfy_pri(*prip)) != FMEV_OK)
186*12967Sgavin.maltby@oracle.com 		return (rc);
187*12967Sgavin.maltby@oracle.com 
188*12967Sgavin.maltby@oracle.com 	return (FMEV_OK);
189*12967Sgavin.maltby@oracle.com }
190*12967Sgavin.maltby@oracle.com 
191*12967Sgavin.maltby@oracle.com uint_t fmev_va2nvl_maxtuples = 100;
192*12967Sgavin.maltby@oracle.com 
193*12967Sgavin.maltby@oracle.com fmev_err_t
va2nvl(nvlist_t ** nvlp,va_list ap,uint_t ntuples)194*12967Sgavin.maltby@oracle.com va2nvl(nvlist_t **nvlp, va_list ap, uint_t ntuples)
195*12967Sgavin.maltby@oracle.com {
196*12967Sgavin.maltby@oracle.com 	nvlist_t *nvl = NULL;
197*12967Sgavin.maltby@oracle.com 	uint_t processed = 0;
198*12967Sgavin.maltby@oracle.com 	char *name;
199*12967Sgavin.maltby@oracle.com 
200*12967Sgavin.maltby@oracle.com 	if (ntuples == 0)
201*12967Sgavin.maltby@oracle.com 		return (FMEVERR_INTERNAL);
202*12967Sgavin.maltby@oracle.com 
203*12967Sgavin.maltby@oracle.com 	if ((name = va_arg(ap, char *)) == NULL || name == FMEV_ARG_TERM)
204*12967Sgavin.maltby@oracle.com 		return (FMEVERR_VARARGS_MALFORMED);
205*12967Sgavin.maltby@oracle.com 
206*12967Sgavin.maltby@oracle.com 	if (ntuples > fmev_va2nvl_maxtuples)
207*12967Sgavin.maltby@oracle.com 		return (FMEVERR_VARARGS_TOOLONG);
208*12967Sgavin.maltby@oracle.com 
209*12967Sgavin.maltby@oracle.com 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
210*12967Sgavin.maltby@oracle.com 		return (FMEVERR_ALLOC);
211*12967Sgavin.maltby@oracle.com 
212*12967Sgavin.maltby@oracle.com 	while (name != NULL && name != FMEV_ARG_TERM && processed <= ntuples) {
213*12967Sgavin.maltby@oracle.com 		data_type_t type;
214*12967Sgavin.maltby@oracle.com 		int err, nelem;
215*12967Sgavin.maltby@oracle.com 
216*12967Sgavin.maltby@oracle.com 		type = va_arg(ap, data_type_t);
217*12967Sgavin.maltby@oracle.com 
218*12967Sgavin.maltby@oracle.com 		switch (type) {
219*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_BYTE:
220*12967Sgavin.maltby@oracle.com 			err = nvlist_add_byte(nvl, name,
221*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uint_t));
222*12967Sgavin.maltby@oracle.com 			break;
223*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_BYTE_ARRAY:
224*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
225*12967Sgavin.maltby@oracle.com 			err = nvlist_add_byte_array(nvl, name,
226*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uchar_t *), nelem);
227*12967Sgavin.maltby@oracle.com 			break;
228*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_BOOLEAN_VALUE:
229*12967Sgavin.maltby@oracle.com 			err = nvlist_add_boolean_value(nvl, name,
230*12967Sgavin.maltby@oracle.com 			    va_arg(ap, boolean_t));
231*12967Sgavin.maltby@oracle.com 			break;
232*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_BOOLEAN_ARRAY:
233*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
234*12967Sgavin.maltby@oracle.com 			err = nvlist_add_boolean_array(nvl, name,
235*12967Sgavin.maltby@oracle.com 			    va_arg(ap, boolean_t *), nelem);
236*12967Sgavin.maltby@oracle.com 			break;
237*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_INT8:
238*12967Sgavin.maltby@oracle.com 			err = nvlist_add_int8(nvl, name,
239*12967Sgavin.maltby@oracle.com 			    va_arg(ap, int));
240*12967Sgavin.maltby@oracle.com 			break;
241*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_INT8_ARRAY:
242*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
243*12967Sgavin.maltby@oracle.com 			err = nvlist_add_int8_array(nvl, name,
244*12967Sgavin.maltby@oracle.com 			    va_arg(ap, int8_t *), nelem);
245*12967Sgavin.maltby@oracle.com 			break;
246*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_UINT8:
247*12967Sgavin.maltby@oracle.com 			err = nvlist_add_uint8(nvl, name,
248*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uint_t));
249*12967Sgavin.maltby@oracle.com 			break;
250*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_UINT8_ARRAY:
251*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
252*12967Sgavin.maltby@oracle.com 			err = nvlist_add_uint8_array(nvl, name,
253*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uint8_t *), nelem);
254*12967Sgavin.maltby@oracle.com 			break;
255*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_INT16:
256*12967Sgavin.maltby@oracle.com 			err = nvlist_add_int16(nvl, name,
257*12967Sgavin.maltby@oracle.com 			    va_arg(ap, int));
258*12967Sgavin.maltby@oracle.com 			break;
259*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_INT16_ARRAY:
260*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
261*12967Sgavin.maltby@oracle.com 			err = nvlist_add_int16_array(nvl, name,
262*12967Sgavin.maltby@oracle.com 			    va_arg(ap, int16_t *), nelem);
263*12967Sgavin.maltby@oracle.com 			break;
264*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_UINT16:
265*12967Sgavin.maltby@oracle.com 			err = nvlist_add_uint16(nvl, name,
266*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uint_t));
267*12967Sgavin.maltby@oracle.com 			break;
268*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_UINT16_ARRAY:
269*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
270*12967Sgavin.maltby@oracle.com 			err = nvlist_add_uint16_array(nvl, name,
271*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uint16_t *), nelem);
272*12967Sgavin.maltby@oracle.com 			break;
273*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_INT32:
274*12967Sgavin.maltby@oracle.com 			err = nvlist_add_int32(nvl, name,
275*12967Sgavin.maltby@oracle.com 			    va_arg(ap, int32_t));
276*12967Sgavin.maltby@oracle.com 			break;
277*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_INT32_ARRAY:
278*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
279*12967Sgavin.maltby@oracle.com 			err = nvlist_add_int32_array(nvl, name,
280*12967Sgavin.maltby@oracle.com 			    va_arg(ap, int32_t *), nelem);
281*12967Sgavin.maltby@oracle.com 			break;
282*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_UINT32:
283*12967Sgavin.maltby@oracle.com 			err = nvlist_add_uint32(nvl, name,
284*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uint32_t));
285*12967Sgavin.maltby@oracle.com 			break;
286*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_UINT32_ARRAY:
287*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
288*12967Sgavin.maltby@oracle.com 			err = nvlist_add_uint32_array(nvl, name,
289*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uint32_t *), nelem);
290*12967Sgavin.maltby@oracle.com 			break;
291*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_INT64:
292*12967Sgavin.maltby@oracle.com 			err = nvlist_add_int64(nvl, name,
293*12967Sgavin.maltby@oracle.com 			    va_arg(ap, int64_t));
294*12967Sgavin.maltby@oracle.com 			break;
295*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_INT64_ARRAY:
296*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
297*12967Sgavin.maltby@oracle.com 			err = nvlist_add_int64_array(nvl, name,
298*12967Sgavin.maltby@oracle.com 			    va_arg(ap, int64_t *), nelem);
299*12967Sgavin.maltby@oracle.com 			break;
300*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_UINT64:
301*12967Sgavin.maltby@oracle.com 			err = nvlist_add_uint64(nvl, name,
302*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uint64_t));
303*12967Sgavin.maltby@oracle.com 			break;
304*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_UINT64_ARRAY:
305*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
306*12967Sgavin.maltby@oracle.com 			err = nvlist_add_uint64_array(nvl, name,
307*12967Sgavin.maltby@oracle.com 			    va_arg(ap, uint64_t *), nelem);
308*12967Sgavin.maltby@oracle.com 			break;
309*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_STRING:
310*12967Sgavin.maltby@oracle.com 			err = nvlist_add_string(nvl, name,
311*12967Sgavin.maltby@oracle.com 			    va_arg(ap, char *));
312*12967Sgavin.maltby@oracle.com 			break;
313*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_STRING_ARRAY:
314*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
315*12967Sgavin.maltby@oracle.com 			err = nvlist_add_string_array(nvl, name,
316*12967Sgavin.maltby@oracle.com 			    va_arg(ap, char **), nelem);
317*12967Sgavin.maltby@oracle.com 			break;
318*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_NVLIST:
319*12967Sgavin.maltby@oracle.com 			err = nvlist_add_nvlist(nvl, name,
320*12967Sgavin.maltby@oracle.com 			    va_arg(ap, nvlist_t *));
321*12967Sgavin.maltby@oracle.com 			break;
322*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_NVLIST_ARRAY:
323*12967Sgavin.maltby@oracle.com 			nelem = va_arg(ap, int);
324*12967Sgavin.maltby@oracle.com 			err = nvlist_add_nvlist_array(nvl, name,
325*12967Sgavin.maltby@oracle.com 			    va_arg(ap, nvlist_t **), nelem);
326*12967Sgavin.maltby@oracle.com 			break;
327*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_HRTIME:
328*12967Sgavin.maltby@oracle.com 			err = nvlist_add_hrtime(nvl, name,
329*12967Sgavin.maltby@oracle.com 			    va_arg(ap, hrtime_t));
330*12967Sgavin.maltby@oracle.com 			break;
331*12967Sgavin.maltby@oracle.com 		case DATA_TYPE_DOUBLE:
332*12967Sgavin.maltby@oracle.com 			err = nvlist_add_double(nvl, name,
333*12967Sgavin.maltby@oracle.com 			    va_arg(ap, double));
334*12967Sgavin.maltby@oracle.com 			break;
335*12967Sgavin.maltby@oracle.com 		default:
336*12967Sgavin.maltby@oracle.com 			err = EINVAL;
337*12967Sgavin.maltby@oracle.com 		}
338*12967Sgavin.maltby@oracle.com 
339*12967Sgavin.maltby@oracle.com 		if (err)
340*12967Sgavin.maltby@oracle.com 			break;	/* terminate on first error */
341*12967Sgavin.maltby@oracle.com 
342*12967Sgavin.maltby@oracle.com 		processed++;
343*12967Sgavin.maltby@oracle.com 		name = va_arg(ap, char *);
344*12967Sgavin.maltby@oracle.com 	}
345*12967Sgavin.maltby@oracle.com 
346*12967Sgavin.maltby@oracle.com 	if (name != FMEV_ARG_TERM || processed != ntuples) {
347*12967Sgavin.maltby@oracle.com 		*nvlp = NULL;
348*12967Sgavin.maltby@oracle.com 		nvlist_free(nvl);
349*12967Sgavin.maltby@oracle.com 		return (FMEVERR_VARARGS_MALFORMED);
350*12967Sgavin.maltby@oracle.com 	}
351*12967Sgavin.maltby@oracle.com 
352*12967Sgavin.maltby@oracle.com 	*nvlp = nvl;
353*12967Sgavin.maltby@oracle.com 	return (FMEV_SUCCESS);
354*12967Sgavin.maltby@oracle.com }
355*12967Sgavin.maltby@oracle.com 
356*12967Sgavin.maltby@oracle.com static fmev_err_t
do_publish(const char * file,const char * func,int64_t line,const char * ruleset,const char * class,const char * subclass,fmev_pri_t pri,nvlist_t * nvl,uint_t ntuples,va_list ap)357*12967Sgavin.maltby@oracle.com do_publish(const char *file, const char *func, int64_t line,
358*12967Sgavin.maltby@oracle.com     const char *ruleset, const char *class, const char *subclass,
359*12967Sgavin.maltby@oracle.com     fmev_pri_t pri, nvlist_t *nvl, uint_t ntuples, va_list ap)
360*12967Sgavin.maltby@oracle.com {
361*12967Sgavin.maltby@oracle.com 	fmev_err_t rc = FMEVERR_INTERNAL;
362*12967Sgavin.maltby@oracle.com 	boolean_t priv = B_TRUE;
363*12967Sgavin.maltby@oracle.com 	nvlist_t *tmpnvl = NULL;
364*12967Sgavin.maltby@oracle.com 	nvlist_t *pub;
365*12967Sgavin.maltby@oracle.com 	evchan_t *evc;
366*12967Sgavin.maltby@oracle.com 
367*12967Sgavin.maltby@oracle.com 	if (nvl) {
368*12967Sgavin.maltby@oracle.com 		ASSERT(ntuples == 0);
369*12967Sgavin.maltby@oracle.com 
370*12967Sgavin.maltby@oracle.com 		/*
371*12967Sgavin.maltby@oracle.com 		 * Enforce NV_UNIQUE_NAME
372*12967Sgavin.maltby@oracle.com 		 */
373*12967Sgavin.maltby@oracle.com 		if ((nvlist_nvflag(nvl) & NV_UNIQUE_NAME) != NV_UNIQUE_NAME)
374*12967Sgavin.maltby@oracle.com 			return (FMEVERR_NVLIST);
375*12967Sgavin.maltby@oracle.com 
376*12967Sgavin.maltby@oracle.com 		pub = nvl;
377*12967Sgavin.maltby@oracle.com 
378*12967Sgavin.maltby@oracle.com 	} else if (ntuples != 0) {
379*12967Sgavin.maltby@oracle.com 		fmev_err_t err;
380*12967Sgavin.maltby@oracle.com 
381*12967Sgavin.maltby@oracle.com 		err = va2nvl(&tmpnvl, ap, ntuples);
382*12967Sgavin.maltby@oracle.com 		if (err != FMEV_SUCCESS)
383*12967Sgavin.maltby@oracle.com 			return (err);
384*12967Sgavin.maltby@oracle.com 
385*12967Sgavin.maltby@oracle.com 		pub = tmpnvl;
386*12967Sgavin.maltby@oracle.com 	} else {
387*12967Sgavin.maltby@oracle.com 		/*
388*12967Sgavin.maltby@oracle.com 		 * Even if the caller has no tuples to publish (just an event
389*12967Sgavin.maltby@oracle.com 		 * class and subclass), we are going to add some detector
390*12967Sgavin.maltby@oracle.com 		 * information so we need some nvlist.
391*12967Sgavin.maltby@oracle.com 		 */
392*12967Sgavin.maltby@oracle.com 		if (nvlist_alloc(&tmpnvl, NV_UNIQUE_NAME, 0) != 0)
393*12967Sgavin.maltby@oracle.com 			return (FMEVERR_ALLOC);
394*12967Sgavin.maltby@oracle.com 
395*12967Sgavin.maltby@oracle.com 		pub = tmpnvl;
396*12967Sgavin.maltby@oracle.com 	}
397*12967Sgavin.maltby@oracle.com 
398*12967Sgavin.maltby@oracle.com 	evc = bind_channel(priv, pri);
399*12967Sgavin.maltby@oracle.com 
400*12967Sgavin.maltby@oracle.com 	if (evc == NULL) {
401*12967Sgavin.maltby@oracle.com 		rc = FMEVERR_INTERNAL;
402*12967Sgavin.maltby@oracle.com 		goto done;
403*12967Sgavin.maltby@oracle.com 	}
404*12967Sgavin.maltby@oracle.com 
405*12967Sgavin.maltby@oracle.com 
406*12967Sgavin.maltby@oracle.com 	/*
407*12967Sgavin.maltby@oracle.com 	 * Add detector information
408*12967Sgavin.maltby@oracle.com 	 */
409*12967Sgavin.maltby@oracle.com 	if (file && nvlist_add_string(pub, "__fmev_file", file) != 0 ||
410*12967Sgavin.maltby@oracle.com 	    func && nvlist_add_string(pub, "__fmev_func", func) != 0 ||
411*12967Sgavin.maltby@oracle.com 	    line != -1 && nvlist_add_int64(pub, "__fmev_line", line) != 0 ||
412*12967Sgavin.maltby@oracle.com 	    nvlist_add_int32(pub, "__fmev_pid", getpid()) != 0 ||
413*12967Sgavin.maltby@oracle.com 	    nvlist_add_string(pub, "__fmev_execname", getexecname()) != 0) {
414*12967Sgavin.maltby@oracle.com 		rc = FMEVERR_ALLOC;
415*12967Sgavin.maltby@oracle.com 		goto done;
416*12967Sgavin.maltby@oracle.com 	}
417*12967Sgavin.maltby@oracle.com 
418*12967Sgavin.maltby@oracle.com 	if (ruleset == NULL)
419*12967Sgavin.maltby@oracle.com 		ruleset = FMEV_RULESET_DEFAULT;
420*12967Sgavin.maltby@oracle.com 
421*12967Sgavin.maltby@oracle.com 	/*
422*12967Sgavin.maltby@oracle.com 	 * We abuse the GPEC publication arguments as follows:
423*12967Sgavin.maltby@oracle.com 	 *
424*12967Sgavin.maltby@oracle.com 	 * GPEC argument	Our usage
425*12967Sgavin.maltby@oracle.com 	 * -------------------- -----------------
426*12967Sgavin.maltby@oracle.com 	 * const char *class	Raw class
427*12967Sgavin.maltby@oracle.com 	 * const char *subclass	Raw subclass
428*12967Sgavin.maltby@oracle.com 	 * const char *vendor	Ruleset name
429*12967Sgavin.maltby@oracle.com 	 * const char *pub_name	Unused
430*12967Sgavin.maltby@oracle.com 	 * nvlist_t *attr_list	Event attributes
431*12967Sgavin.maltby@oracle.com 	 */
432*12967Sgavin.maltby@oracle.com 	rc = (sysevent_evc_publish(evc, class, subclass, ruleset, "",
433*12967Sgavin.maltby@oracle.com 	    pub, EVCH_NOSLEEP) == 0) ? FMEV_SUCCESS : FMEVERR_TRANSPORT;
434*12967Sgavin.maltby@oracle.com 
435*12967Sgavin.maltby@oracle.com done:
436*12967Sgavin.maltby@oracle.com 	/* Free a passed in nvlist iff success */
437*12967Sgavin.maltby@oracle.com 	if (nvl && rc == FMEV_SUCCESS)
438*12967Sgavin.maltby@oracle.com 		nvlist_free(nvl);
439*12967Sgavin.maltby@oracle.com 
440*12967Sgavin.maltby@oracle.com 	if (tmpnvl)
441*12967Sgavin.maltby@oracle.com 		nvlist_free(tmpnvl);
442*12967Sgavin.maltby@oracle.com 
443*12967Sgavin.maltby@oracle.com 	return (rc);
444*12967Sgavin.maltby@oracle.com }
445*12967Sgavin.maltby@oracle.com 
446*12967Sgavin.maltby@oracle.com fmev_err_t
_i_fmev_publish_nvl(const char * file,const char * func,int64_t line,const char * ruleset,const char * class,const char * subclass,fmev_pri_t pri,nvlist_t * attr)447*12967Sgavin.maltby@oracle.com _i_fmev_publish_nvl(
448*12967Sgavin.maltby@oracle.com     const char *file, const char *func, int64_t line,
449*12967Sgavin.maltby@oracle.com     const char *ruleset, const char *class, const char *subclass,
450*12967Sgavin.maltby@oracle.com     fmev_pri_t pri, nvlist_t *attr)
451*12967Sgavin.maltby@oracle.com {
452*12967Sgavin.maltby@oracle.com 	fmev_err_t rc;
453*12967Sgavin.maltby@oracle.com 
454*12967Sgavin.maltby@oracle.com 	if ((rc = vrfy(&ruleset, &class, &subclass, &pri)) != FMEV_OK)
455*12967Sgavin.maltby@oracle.com 		return (rc);		/* any attr not freed */
456*12967Sgavin.maltby@oracle.com 
457*12967Sgavin.maltby@oracle.com 	return (do_publish(file, func, line,
458*12967Sgavin.maltby@oracle.com 	    ruleset, class, subclass,
459*12967Sgavin.maltby@oracle.com 	    pri, attr, 0, NULL));	/* any attr freed iff success */
460*12967Sgavin.maltby@oracle.com }
461*12967Sgavin.maltby@oracle.com 
462*12967Sgavin.maltby@oracle.com fmev_err_t
_i_fmev_publish(const char * file,const char * func,int64_t line,const char * ruleset,const char * class,const char * subclass,fmev_pri_t pri,uint_t ntuples,...)463*12967Sgavin.maltby@oracle.com _i_fmev_publish(
464*12967Sgavin.maltby@oracle.com     const char *file, const char *func, int64_t line,
465*12967Sgavin.maltby@oracle.com     const char *ruleset, const char *class, const char *subclass,
466*12967Sgavin.maltby@oracle.com     fmev_pri_t pri,
467*12967Sgavin.maltby@oracle.com     uint_t ntuples, ...)
468*12967Sgavin.maltby@oracle.com {
469*12967Sgavin.maltby@oracle.com 	va_list ap;
470*12967Sgavin.maltby@oracle.com 	fmev_err_t rc;
471*12967Sgavin.maltby@oracle.com 
472*12967Sgavin.maltby@oracle.com 	if ((rc = vrfy(&ruleset, &class, &subclass, &pri)) != FMEV_OK)
473*12967Sgavin.maltby@oracle.com 		return (rc);
474*12967Sgavin.maltby@oracle.com 
475*12967Sgavin.maltby@oracle.com 	if (ntuples != 0)
476*12967Sgavin.maltby@oracle.com 		va_start(ap, ntuples);
477*12967Sgavin.maltby@oracle.com 
478*12967Sgavin.maltby@oracle.com 	rc = do_publish(file, func, line,
479*12967Sgavin.maltby@oracle.com 	    ruleset, class, subclass,
480*12967Sgavin.maltby@oracle.com 	    pri, NULL, ntuples, ap);
481*12967Sgavin.maltby@oracle.com 
482*12967Sgavin.maltby@oracle.com 	if (ntuples != 0)
483*12967Sgavin.maltby@oracle.com 		va_end(ap);
484*12967Sgavin.maltby@oracle.com 
485*12967Sgavin.maltby@oracle.com 	return (rc);
486*12967Sgavin.maltby@oracle.com }
487*12967Sgavin.maltby@oracle.com 
488*12967Sgavin.maltby@oracle.com 
489*12967Sgavin.maltby@oracle.com #pragma	weak fmev_publish = _fmev_publish
490*12967Sgavin.maltby@oracle.com #pragma	weak fmev_rspublish = _fmev_rspublish
491*12967Sgavin.maltby@oracle.com 
492*12967Sgavin.maltby@oracle.com static fmev_err_t
_fmev_publish(const char * class,const char * subclass,fmev_pri_t pri,uint_t ntuples,...)493*12967Sgavin.maltby@oracle.com _fmev_publish(const char *class, const char *subclass, fmev_pri_t pri,
494*12967Sgavin.maltby@oracle.com     uint_t ntuples, ...)
495*12967Sgavin.maltby@oracle.com {
496*12967Sgavin.maltby@oracle.com 	fmev_err_t rc;
497*12967Sgavin.maltby@oracle.com 	va_list ap;
498*12967Sgavin.maltby@oracle.com 
499*12967Sgavin.maltby@oracle.com 	if ((rc = vrfy(NULL, &class, &subclass, &pri)) != FMEV_OK)
500*12967Sgavin.maltby@oracle.com 		return (rc);
501*12967Sgavin.maltby@oracle.com 
502*12967Sgavin.maltby@oracle.com 	if (ntuples != 0)
503*12967Sgavin.maltby@oracle.com 		va_start(ap, ntuples);
504*12967Sgavin.maltby@oracle.com 
505*12967Sgavin.maltby@oracle.com 	rc = do_publish(NULL, NULL, -1,
506*12967Sgavin.maltby@oracle.com 	    FMEV_RULESET_DEFAULT, class, subclass,
507*12967Sgavin.maltby@oracle.com 	    pri, NULL, ntuples, ap);
508*12967Sgavin.maltby@oracle.com 
509*12967Sgavin.maltby@oracle.com 	if (ntuples != 0)
510*12967Sgavin.maltby@oracle.com 		va_end(ap);
511*12967Sgavin.maltby@oracle.com 
512*12967Sgavin.maltby@oracle.com 	return (rc);
513*12967Sgavin.maltby@oracle.com }
514*12967Sgavin.maltby@oracle.com 
515*12967Sgavin.maltby@oracle.com static fmev_err_t
_fmev_rspublish(const char * ruleset,const char * class,const char * subclass,fmev_pri_t pri,uint_t ntuples,...)516*12967Sgavin.maltby@oracle.com _fmev_rspublish(const char *ruleset, const char *class, const char *subclass,
517*12967Sgavin.maltby@oracle.com     fmev_pri_t pri, uint_t ntuples, ...)
518*12967Sgavin.maltby@oracle.com {
519*12967Sgavin.maltby@oracle.com 	fmev_err_t rc;
520*12967Sgavin.maltby@oracle.com 	va_list ap;
521*12967Sgavin.maltby@oracle.com 
522*12967Sgavin.maltby@oracle.com 	if ((rc = vrfy(&ruleset, &class, &subclass, &pri)) != FMEV_OK)
523*12967Sgavin.maltby@oracle.com 		return (rc);
524*12967Sgavin.maltby@oracle.com 
525*12967Sgavin.maltby@oracle.com 	if (ntuples != 0)
526*12967Sgavin.maltby@oracle.com 		va_start(ap, ntuples);
527*12967Sgavin.maltby@oracle.com 
528*12967Sgavin.maltby@oracle.com 	rc = do_publish(NULL, NULL, -1,
529*12967Sgavin.maltby@oracle.com 	    ruleset, class, subclass,
530*12967Sgavin.maltby@oracle.com 	    pri, NULL, ntuples, ap);
531*12967Sgavin.maltby@oracle.com 
532*12967Sgavin.maltby@oracle.com 	if (ntuples != 0)
533*12967Sgavin.maltby@oracle.com 		va_end(ap);
534*12967Sgavin.maltby@oracle.com 
535*12967Sgavin.maltby@oracle.com 	return (rc);
536*12967Sgavin.maltby@oracle.com }
537