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