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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Subscription event access interfaces.
28 */
29
30 #include <sys/types.h>
31 #include <limits.h>
32 #include <atomic.h>
33 #include <libsysevent.h>
34 #include <umem.h>
35 #include <fm/libfmevent.h>
36 #include <sys/fm/protocol.h>
37
38 #include "fmev_impl.h"
39
40 #define FMEV_API_ENTER(iep, v) \
41 fmev_api_enter(fmev_shdl_cmn(((iep)->ei_hdl)), LIBFMEVENT_VERSION_##v)
42
43 typedef struct {
44 uint32_t ei_magic; /* _FMEVMAGIC */
45 volatile uint32_t ei_refcnt; /* reference count */
46 fmev_shdl_t ei_hdl; /* handle received on */
47 nvlist_t *ei_nvl; /* (duped) sysevent attribute list */
48 uint64_t ei_fmtime[2]; /* embedded protocol event time */
49 } fmev_impl_t;
50
51 #define FMEV2IMPL(ev) ((fmev_impl_t *)(ev))
52 #define IMPL2FMEV(iep) ((fmev_t)(iep))
53
54 #define _FMEVMAGIC 0x466d4576 /* "FmEv" */
55
56 #define EVENT_VALID(iep) ((iep)->ei_magic == _FMEVMAGIC && \
57 (iep)->ei_refcnt > 0 && fmev_shdl_valid((iep)->ei_hdl))
58
59 #define FM_TIME_SEC 0
60 #define FM_TIME_NSEC 1
61
62 /*
63 * Transform a received sysevent_t into an fmev_t.
64 */
65
66 uint64_t fmev_bad_attr, fmev_bad_tod, fmev_bad_class;
67
68 fmev_t
fmev_sysev2fmev(fmev_shdl_t hdl,sysevent_t * sep,char ** clsp,nvlist_t ** nvlp)69 fmev_sysev2fmev(fmev_shdl_t hdl, sysevent_t *sep, char **clsp, nvlist_t **nvlp)
70 {
71 fmev_impl_t *iep;
72 uint64_t *tod;
73 uint_t nelem;
74
75 if ((iep = fmev_shdl_alloc(hdl, sizeof (*iep))) == NULL)
76 return (NULL);
77
78 /*
79 * sysevent_get_attr_list duplicates the nvlist - we free it
80 * in fmev_free when the reference count hits zero.
81 */
82 if (sysevent_get_attr_list(sep, &iep->ei_nvl) != 0) {
83 fmev_shdl_free(hdl, iep, sizeof (*iep));
84 fmev_bad_attr++;
85 return (NULL);
86 }
87
88 *nvlp = iep->ei_nvl;
89
90 if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, clsp) != 0) {
91 nvlist_free(iep->ei_nvl);
92 fmev_shdl_free(hdl, iep, sizeof (*iep));
93 fmev_bad_class++;
94 return (NULL);
95 }
96
97 if (nvlist_lookup_uint64_array(iep->ei_nvl, "__tod", &tod,
98 &nelem) != 0 || nelem != 2) {
99 nvlist_free(iep->ei_nvl);
100 fmev_shdl_free(hdl, iep, sizeof (*iep));
101 fmev_bad_tod++;
102 return (NULL);
103 }
104
105 iep->ei_fmtime[FM_TIME_SEC] = tod[0];
106 iep->ei_fmtime[FM_TIME_NSEC] = tod[1];
107
108 /*
109 * Now remove the fmd-private __tod and __ttl members.
110 */
111 (void) nvlist_remove_all(iep->ei_nvl, "__tod");
112 (void) nvlist_remove_all(iep->ei_nvl, "__ttl");
113
114 iep->ei_magic = _FMEVMAGIC;
115 iep->ei_hdl = hdl;
116 iep->ei_refcnt = 1;
117 ASSERT(EVENT_VALID(iep));
118
119 return (IMPL2FMEV(iep));
120 }
121
122 static void
fmev_free(fmev_impl_t * iep)123 fmev_free(fmev_impl_t *iep)
124 {
125 ASSERT(iep->ei_refcnt == 0);
126
127 nvlist_free(iep->ei_nvl);
128 fmev_shdl_free(iep->ei_hdl, iep, sizeof (*iep));
129 }
130
131 void
fmev_hold(fmev_t ev)132 fmev_hold(fmev_t ev)
133 {
134 fmev_impl_t *iep = FMEV2IMPL(ev);
135
136 ASSERT(EVENT_VALID(iep));
137
138 (void) FMEV_API_ENTER(iep, 1);
139
140 atomic_inc_32(&iep->ei_refcnt);
141 }
142
143 void
fmev_rele(fmev_t ev)144 fmev_rele(fmev_t ev)
145 {
146 fmev_impl_t *iep = FMEV2IMPL(ev);
147
148 ASSERT(EVENT_VALID(iep));
149
150 (void) FMEV_API_ENTER(iep, 1);
151
152 if (atomic_dec_32_nv(&iep->ei_refcnt) == 0)
153 fmev_free(iep);
154 }
155
156 fmev_t
fmev_dup(fmev_t ev)157 fmev_dup(fmev_t ev)
158 {
159 fmev_impl_t *iep = FMEV2IMPL(ev);
160 fmev_impl_t *cp;
161
162 ASSERT(EVENT_VALID(iep));
163
164 if (!FMEV_API_ENTER(iep, 1))
165 return (NULL); /* fmev_errno set */
166
167 if (ev == NULL) {
168 (void) fmev_seterr(FMEVERR_API);
169 return (NULL);
170 }
171
172 if ((cp = fmev_shdl_alloc(iep->ei_hdl, sizeof (*iep))) == NULL) {
173 (void) fmev_seterr(FMEVERR_ALLOC);
174 return (NULL);
175 }
176
177 if (nvlist_dup(iep->ei_nvl, &cp->ei_nvl, 0) != 0) {
178 fmev_shdl_free(iep->ei_hdl, cp, sizeof (*cp));
179 (void) fmev_seterr(FMEVERR_ALLOC);
180 return (NULL);
181 }
182
183 cp->ei_magic = _FMEVMAGIC;
184 cp->ei_hdl = iep->ei_hdl;
185 cp->ei_refcnt = 1;
186 return (IMPL2FMEV(cp));
187 }
188
189 nvlist_t *
fmev_attr_list(fmev_t ev)190 fmev_attr_list(fmev_t ev)
191 {
192 fmev_impl_t *iep = FMEV2IMPL(ev);
193
194 ASSERT(EVENT_VALID(iep));
195
196 if (!FMEV_API_ENTER(iep, 1))
197 return (NULL); /* fmev_errno set */
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 *
fmev_class(fmev_t ev)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 if (!FMEV_API_ENTER(iep, 1))
219 return (NULL); /* fmev_errno set */
220
221 if (ev == NULL) {
222 (void) fmev_seterr(FMEVERR_API);
223 return ("");
224 }
225
226 if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, (char **)&class) != 0 ||
227 *class == '\0') {
228 (void) fmev_seterr(FMEVERR_MALFORMED_EVENT);
229 return ("");
230 }
231
232 return (class);
233 }
234
235 fmev_err_t
fmev_timespec(fmev_t ev,struct timespec * tp)236 fmev_timespec(fmev_t ev, struct timespec *tp)
237 {
238 fmev_impl_t *iep = FMEV2IMPL(ev);
239 uint64_t timetlimit;
240
241 ASSERT(EVENT_VALID(iep));
242 if (!FMEV_API_ENTER(iep, 1))
243 return (fmev_errno);
244
245 #ifdef _LP64
246 timetlimit = INT64_MAX;
247 #else
248 timetlimit = INT32_MAX;
249 #endif
250
251 if (iep->ei_fmtime[FM_TIME_SEC] > timetlimit)
252 return (FMEVERR_OVERFLOW);
253
254 tp->tv_sec = (time_t)iep->ei_fmtime[FM_TIME_SEC];
255 tp->tv_nsec = (long)iep->ei_fmtime[FM_TIME_NSEC];
256
257 return (FMEV_SUCCESS);
258 }
259
260 uint64_t
fmev_time_sec(fmev_t ev)261 fmev_time_sec(fmev_t ev)
262 {
263 return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_SEC]);
264 }
265
266 uint64_t
fmev_time_nsec(fmev_t ev)267 fmev_time_nsec(fmev_t ev)
268 {
269 return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_NSEC]);
270 }
271
272 struct tm *
fmev_localtime(fmev_t ev,struct tm * tm)273 fmev_localtime(fmev_t ev, struct tm *tm)
274 {
275 time_t seconds;
276
277 seconds = (time_t)fmev_time_sec(ev);
278 return (localtime_r(&seconds, tm));
279 }
280
281 fmev_shdl_t
fmev_ev2shdl(fmev_t ev)282 fmev_ev2shdl(fmev_t ev)
283 {
284 fmev_impl_t *iep = FMEV2IMPL(ev);
285
286 if (!FMEV_API_ENTER(iep, 2))
287 return (NULL);
288
289 return (iep->ei_hdl);
290 }
291