1*49b225e1SGavin Maltby /*
2*49b225e1SGavin Maltby  * CDDL HEADER START
3*49b225e1SGavin Maltby  *
4*49b225e1SGavin Maltby  * The contents of this file are subject to the terms of the
5*49b225e1SGavin Maltby  * Common Development and Distribution License (the "License").
6*49b225e1SGavin Maltby  * You may not use this file except in compliance with the License.
7*49b225e1SGavin Maltby  *
8*49b225e1SGavin Maltby  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*49b225e1SGavin Maltby  * or http://www.opensolaris.org/os/licensing.
10*49b225e1SGavin Maltby  * See the License for the specific language governing permissions
11*49b225e1SGavin Maltby  * and limitations under the License.
12*49b225e1SGavin Maltby  *
13*49b225e1SGavin Maltby  * When distributing Covered Code, include this CDDL HEADER in each
14*49b225e1SGavin Maltby  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*49b225e1SGavin Maltby  * If applicable, add the following below this CDDL HEADER, with the
16*49b225e1SGavin Maltby  * fields enclosed by brackets "[]" replaced with your own identifying
17*49b225e1SGavin Maltby  * information: Portions Copyright [yyyy] [name of copyright owner]
18*49b225e1SGavin Maltby  *
19*49b225e1SGavin Maltby  * CDDL HEADER END
20*49b225e1SGavin Maltby  */
21*49b225e1SGavin Maltby 
22*49b225e1SGavin Maltby /*
23*49b225e1SGavin Maltby  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*49b225e1SGavin Maltby  * Use is subject to license terms.
25*49b225e1SGavin Maltby  */
26*49b225e1SGavin Maltby 
27*49b225e1SGavin Maltby /*
28*49b225e1SGavin Maltby  * Subscription event access interfaces.
29*49b225e1SGavin Maltby  */
30*49b225e1SGavin Maltby 
31*49b225e1SGavin Maltby #include <sys/types.h>
32*49b225e1SGavin Maltby #include <limits.h>
33*49b225e1SGavin Maltby #include <atomic.h>
34*49b225e1SGavin Maltby #include <libsysevent.h>
35*49b225e1SGavin Maltby #include <umem.h>
36*49b225e1SGavin Maltby #include <fm/libfmevent.h>
37*49b225e1SGavin Maltby #include <sys/fm/protocol.h>
38*49b225e1SGavin Maltby 
39*49b225e1SGavin Maltby #include "fmev_impl.h"
40*49b225e1SGavin Maltby 
41*49b225e1SGavin Maltby #define	API_ENTERV1(iep) \
42*49b225e1SGavin Maltby 	((void) fmev_api_enter(fmev_shdl_cmn(((iep)->ei_hdl)), \
43*49b225e1SGavin Maltby 	LIBFMEVENT_VERSION_1))
44*49b225e1SGavin Maltby 
45*49b225e1SGavin Maltby typedef struct {
46*49b225e1SGavin Maltby 	uint32_t ei_magic;		/* _FMEVMAGIC */
47*49b225e1SGavin Maltby 	volatile uint32_t ei_refcnt;	/* reference count */
48*49b225e1SGavin Maltby 	fmev_shdl_t ei_hdl;		/* handle received on */
49*49b225e1SGavin Maltby 	nvlist_t *ei_nvl;		/* (duped) sysevent attribute list */
50*49b225e1SGavin Maltby 	uint64_t ei_fmtime[2];		/* embedded protocol event time */
51*49b225e1SGavin Maltby } fmev_impl_t;
52*49b225e1SGavin Maltby 
53*49b225e1SGavin Maltby #define	FMEV2IMPL(ev)	((fmev_impl_t *)(ev))
54*49b225e1SGavin Maltby #define	IMPL2FMEV(iep)	((fmev_t)(iep))
55*49b225e1SGavin Maltby 
56*49b225e1SGavin Maltby #define	_FMEVMAGIC	0x466d4576	/* "FmEv" */
57*49b225e1SGavin Maltby 
58*49b225e1SGavin Maltby #define	EVENT_VALID(iep) ((iep)->ei_magic == _FMEVMAGIC && \
59*49b225e1SGavin Maltby 	(iep)->ei_refcnt > 0 && fmev_shdl_valid((iep)->ei_hdl))
60*49b225e1SGavin Maltby 
61*49b225e1SGavin Maltby #define	FM_TIME_SEC	0
62*49b225e1SGavin Maltby #define	FM_TIME_NSEC	1
63*49b225e1SGavin Maltby 
64*49b225e1SGavin Maltby /*
65*49b225e1SGavin Maltby  * Transform a received sysevent_t into an fmev_t.
66*49b225e1SGavin Maltby  */
67*49b225e1SGavin Maltby 
68*49b225e1SGavin Maltby uint64_t fmev_bad_attr, fmev_bad_tod, fmev_bad_class;
69*49b225e1SGavin Maltby 
70*49b225e1SGavin Maltby fmev_t
71*49b225e1SGavin Maltby fmev_sysev2fmev(fmev_shdl_t hdl, sysevent_t *sep, char **clsp, nvlist_t **nvlp)
72*49b225e1SGavin Maltby {
73*49b225e1SGavin Maltby 	fmev_impl_t *iep;
74*49b225e1SGavin Maltby 	uint64_t *tod;
75*49b225e1SGavin Maltby 	uint_t nelem;
76*49b225e1SGavin Maltby 
77*49b225e1SGavin Maltby 	if ((iep = fmev_shdl_alloc(hdl, sizeof (*iep))) == NULL)
78*49b225e1SGavin Maltby 		return (NULL);
79*49b225e1SGavin Maltby 
80*49b225e1SGavin Maltby 	/*
81*49b225e1SGavin Maltby 	 * sysevent_get_attr_list duplicates the nvlist - we free it
82*49b225e1SGavin Maltby 	 * in fmev_free when the reference count hits zero.
83*49b225e1SGavin Maltby 	 */
84*49b225e1SGavin Maltby 	if (sysevent_get_attr_list(sep, &iep->ei_nvl) != 0) {
85*49b225e1SGavin Maltby 		fmev_shdl_free(hdl, iep, sizeof (*iep));
86*49b225e1SGavin Maltby 		fmev_bad_attr++;
87*49b225e1SGavin Maltby 		return (NULL);
88*49b225e1SGavin Maltby 	}
89*49b225e1SGavin Maltby 
90*49b225e1SGavin Maltby 	*nvlp = iep->ei_nvl;
91*49b225e1SGavin Maltby 
92*49b225e1SGavin Maltby 	if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, clsp) != 0) {
93*49b225e1SGavin Maltby 		nvlist_free(iep->ei_nvl);
94*49b225e1SGavin Maltby 		fmev_shdl_free(hdl, iep, sizeof (*iep));
95*49b225e1SGavin Maltby 		fmev_bad_class++;
96*49b225e1SGavin Maltby 		return (NULL);
97*49b225e1SGavin Maltby 	}
98*49b225e1SGavin Maltby 
99*49b225e1SGavin Maltby 	if (nvlist_lookup_uint64_array(iep->ei_nvl, "__tod", &tod,
100*49b225e1SGavin Maltby 	    &nelem) != 0 || nelem != 2) {
101*49b225e1SGavin Maltby 		nvlist_free(iep->ei_nvl);
102*49b225e1SGavin Maltby 		fmev_shdl_free(hdl, iep, sizeof (*iep));
103*49b225e1SGavin Maltby 		fmev_bad_tod++;
104*49b225e1SGavin Maltby 		return (NULL);
105*49b225e1SGavin Maltby 	}
106*49b225e1SGavin Maltby 
107*49b225e1SGavin Maltby 	iep->ei_fmtime[FM_TIME_SEC] = tod[0];
108*49b225e1SGavin Maltby 	iep->ei_fmtime[FM_TIME_NSEC] = tod[1];
109*49b225e1SGavin Maltby 
110*49b225e1SGavin Maltby 	/*
111*49b225e1SGavin Maltby 	 * Now remove the fmd-private __tod and __ttl members.
112*49b225e1SGavin Maltby 	 */
113*49b225e1SGavin Maltby 	(void) nvlist_remove_all(iep->ei_nvl, "__tod");
114*49b225e1SGavin Maltby 	(void) nvlist_remove_all(iep->ei_nvl, "__ttl");
115*49b225e1SGavin Maltby 
116*49b225e1SGavin Maltby 	iep->ei_magic = _FMEVMAGIC;
117*49b225e1SGavin Maltby 	iep->ei_hdl = hdl;
118*49b225e1SGavin Maltby 	iep->ei_refcnt = 1;
119*49b225e1SGavin Maltby 	ASSERT(EVENT_VALID(iep));
120*49b225e1SGavin Maltby 
121*49b225e1SGavin Maltby 	return (IMPL2FMEV(iep));
122*49b225e1SGavin Maltby }
123*49b225e1SGavin Maltby 
124*49b225e1SGavin Maltby static void
125*49b225e1SGavin Maltby fmev_free(fmev_impl_t *iep)
126*49b225e1SGavin Maltby {
127*49b225e1SGavin Maltby 	ASSERT(iep->ei_refcnt == 0);
128*49b225e1SGavin Maltby 
129*49b225e1SGavin Maltby 	nvlist_free(iep->ei_nvl);
130*49b225e1SGavin Maltby 	fmev_shdl_free(iep->ei_hdl, iep, sizeof (*iep));
131*49b225e1SGavin Maltby }
132*49b225e1SGavin Maltby 
133*49b225e1SGavin Maltby void
134*49b225e1SGavin Maltby fmev_hold(fmev_t ev)
135*49b225e1SGavin Maltby {
136*49b225e1SGavin Maltby 	fmev_impl_t *iep = FMEV2IMPL(ev);
137*49b225e1SGavin Maltby 
138*49b225e1SGavin Maltby 	ASSERT(EVENT_VALID(iep));
139*49b225e1SGavin Maltby 
140*49b225e1SGavin Maltby 	API_ENTERV1(iep);
141*49b225e1SGavin Maltby 
142*49b225e1SGavin Maltby 	atomic_inc_32(&iep->ei_refcnt);
143*49b225e1SGavin Maltby }
144*49b225e1SGavin Maltby 
145*49b225e1SGavin Maltby void
146*49b225e1SGavin Maltby fmev_rele(fmev_t ev)
147*49b225e1SGavin Maltby {
148*49b225e1SGavin Maltby 	fmev_impl_t *iep = FMEV2IMPL(ev);
149*49b225e1SGavin Maltby 
150*49b225e1SGavin Maltby 	ASSERT(EVENT_VALID(iep));
151*49b225e1SGavin Maltby 
152*49b225e1SGavin Maltby 	API_ENTERV1(iep);
153*49b225e1SGavin Maltby 
154*49b225e1SGavin Maltby 	if (atomic_dec_32_nv(&iep->ei_refcnt) == 0)
155*49b225e1SGavin Maltby 		fmev_free(iep);
156*49b225e1SGavin Maltby }
157*49b225e1SGavin Maltby 
158*49b225e1SGavin Maltby fmev_t
159*49b225e1SGavin Maltby fmev_dup(fmev_t ev)
160*49b225e1SGavin Maltby {
161*49b225e1SGavin Maltby 	fmev_impl_t *iep = FMEV2IMPL(ev);
162*49b225e1SGavin Maltby 	fmev_impl_t *cp;
163*49b225e1SGavin Maltby 
164*49b225e1SGavin Maltby 	ASSERT(EVENT_VALID(iep));
165*49b225e1SGavin Maltby 
166*49b225e1SGavin Maltby 	API_ENTERV1(iep);
167*49b225e1SGavin Maltby 
168*49b225e1SGavin Maltby 	if (ev == NULL) {
169*49b225e1SGavin Maltby 		(void) fmev_seterr(FMEVERR_API);
170*49b225e1SGavin Maltby 		return (NULL);
171*49b225e1SGavin Maltby 	}
172*49b225e1SGavin Maltby 
173*49b225e1SGavin Maltby 	if ((cp = fmev_shdl_alloc(iep->ei_hdl, sizeof (*iep))) == NULL) {
174*49b225e1SGavin Maltby 		(void) fmev_seterr(FMEVERR_ALLOC);
175*49b225e1SGavin Maltby 		return (NULL);
176*49b225e1SGavin Maltby 	}
177*49b225e1SGavin Maltby 
178*49b225e1SGavin Maltby 	if (nvlist_dup(iep->ei_nvl, &cp->ei_nvl, 0) != 0) {
179*49b225e1SGavin Maltby 		fmev_shdl_free(iep->ei_hdl, cp, sizeof (*cp));
180*49b225e1SGavin Maltby 		(void) fmev_seterr(FMEVERR_ALLOC);
181*49b225e1SGavin Maltby 		return (NULL);
182*49b225e1SGavin Maltby 	}
183*49b225e1SGavin Maltby 
184*49b225e1SGavin Maltby 	cp->ei_magic = _FMEVMAGIC;
185*49b225e1SGavin Maltby 	cp->ei_hdl = iep->ei_hdl;
186*49b225e1SGavin Maltby 	cp->ei_refcnt = 1;
187*49b225e1SGavin Maltby 	return (IMPL2FMEV(cp));
188*49b225e1SGavin Maltby }
189*49b225e1SGavin Maltby 
190*49b225e1SGavin Maltby nvlist_t *
191*49b225e1SGavin Maltby fmev_attr_list(fmev_t ev)
192*49b225e1SGavin Maltby {
193*49b225e1SGavin Maltby 	fmev_impl_t *iep = FMEV2IMPL(ev);
194*49b225e1SGavin Maltby 
195*49b225e1SGavin Maltby 	ASSERT(EVENT_VALID(iep));
196*49b225e1SGavin Maltby 
197*49b225e1SGavin Maltby 	API_ENTERV1(iep);
198*49b225e1SGavin Maltby 
199*49b225e1SGavin Maltby 	if (ev == NULL) {
200*49b225e1SGavin Maltby 		(void) fmev_seterr(FMEVERR_API);
201*49b225e1SGavin Maltby 		return (NULL);
202*49b225e1SGavin Maltby 	} else if (iep->ei_nvl == NULL) {
203*49b225e1SGavin Maltby 		(void) fmev_seterr(FMEVERR_MALFORMED_EVENT);
204*49b225e1SGavin Maltby 		return (NULL);
205*49b225e1SGavin Maltby 	}
206*49b225e1SGavin Maltby 
207*49b225e1SGavin Maltby 	return (iep->ei_nvl);
208*49b225e1SGavin Maltby }
209*49b225e1SGavin Maltby 
210*49b225e1SGavin Maltby const char *
211*49b225e1SGavin Maltby fmev_class(fmev_t ev)
212*49b225e1SGavin Maltby {
213*49b225e1SGavin Maltby 	fmev_impl_t *iep = FMEV2IMPL(ev);
214*49b225e1SGavin Maltby 	const char *class;
215*49b225e1SGavin Maltby 
216*49b225e1SGavin Maltby 	ASSERT(EVENT_VALID(iep));
217*49b225e1SGavin Maltby 
218*49b225e1SGavin Maltby 	API_ENTERV1(iep);
219*49b225e1SGavin Maltby 
220*49b225e1SGavin Maltby 	if (ev == NULL) {
221*49b225e1SGavin Maltby 		(void) fmev_seterr(FMEVERR_API);
222*49b225e1SGavin Maltby 		return ("");
223*49b225e1SGavin Maltby 	}
224*49b225e1SGavin Maltby 
225*49b225e1SGavin Maltby 	if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, (char **)&class) != 0 ||
226*49b225e1SGavin Maltby 	    *class == '\0') {
227*49b225e1SGavin Maltby 		(void) fmev_seterr(FMEVERR_MALFORMED_EVENT);
228*49b225e1SGavin Maltby 		return ("");
229*49b225e1SGavin Maltby 	}
230*49b225e1SGavin Maltby 
231*49b225e1SGavin Maltby 	return (class);
232*49b225e1SGavin Maltby }
233*49b225e1SGavin Maltby 
234*49b225e1SGavin Maltby fmev_err_t
235*49b225e1SGavin Maltby fmev_timespec(fmev_t ev, struct timespec *tp)
236*49b225e1SGavin Maltby {
237*49b225e1SGavin Maltby 	fmev_impl_t *iep = FMEV2IMPL(ev);
238*49b225e1SGavin Maltby 	uint64_t timetlimit;
239*49b225e1SGavin Maltby 
240*49b225e1SGavin Maltby 	ASSERT(EVENT_VALID(iep));
241*49b225e1SGavin Maltby 	API_ENTERV1(iep);
242*49b225e1SGavin Maltby 
243*49b225e1SGavin Maltby #ifdef	_LP64
244*49b225e1SGavin Maltby 	timetlimit = INT64_MAX;
245*49b225e1SGavin Maltby #else
246*49b225e1SGavin Maltby 	timetlimit = INT32_MAX;
247*49b225e1SGavin Maltby #endif
248*49b225e1SGavin Maltby 
249*49b225e1SGavin Maltby 	if (iep->ei_fmtime[FM_TIME_SEC] > timetlimit)
250*49b225e1SGavin Maltby 		return (FMEVERR_OVERFLOW);
251*49b225e1SGavin Maltby 
252*49b225e1SGavin Maltby 	tp->tv_sec = (time_t)iep->ei_fmtime[FM_TIME_SEC];
253*49b225e1SGavin Maltby 	tp->tv_nsec = (long)iep->ei_fmtime[FM_TIME_NSEC];
254*49b225e1SGavin Maltby 
255*49b225e1SGavin Maltby 	return (FMEV_SUCCESS);
256*49b225e1SGavin Maltby }
257*49b225e1SGavin Maltby 
258*49b225e1SGavin Maltby uint64_t
259*49b225e1SGavin Maltby fmev_time_sec(fmev_t ev)
260*49b225e1SGavin Maltby {
261*49b225e1SGavin Maltby 	return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_SEC]);
262*49b225e1SGavin Maltby }
263*49b225e1SGavin Maltby 
264*49b225e1SGavin Maltby uint64_t
265*49b225e1SGavin Maltby fmev_time_nsec(fmev_t ev)
266*49b225e1SGavin Maltby {
267*49b225e1SGavin Maltby 	return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_NSEC]);
268*49b225e1SGavin Maltby }
269*49b225e1SGavin Maltby 
270*49b225e1SGavin Maltby struct tm *
271*49b225e1SGavin Maltby fmev_localtime(fmev_t ev, struct tm *tm)
272*49b225e1SGavin Maltby {
273*49b225e1SGavin Maltby 	time_t seconds;
274*49b225e1SGavin Maltby 
275*49b225e1SGavin Maltby 	seconds = (time_t)fmev_time_sec(ev);
276*49b225e1SGavin Maltby 	return (localtime_r(&seconds, tm));
277*49b225e1SGavin Maltby }
278