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