1 /*-
2 * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 #ifdef __FreeBSD__
29 __FBSDID("$FreeBSD: head/sys/cddl/compat/opensolaris/kern/opensolaris_sysevent.c 222343 2011-05-27 08:34:31Z pjd $");
30 #endif
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/kmem.h>
36 #ifdef __FreeBSD__
37 #include <sys/sbuf.h>
38 #endif
39 #include <sys/nvpair.h>
40 #include <sys/sunddi.h>
41 #include <sys/sysevent.h>
42 #include <sys/fm/protocol.h>
43
44 struct sysevent {
45 nvlist_t *se_nvl;
46 char se_class[128];
47 char se_subclass[128];
48 char se_pub[128];
49 };
50
51 sysevent_t *
sysevent_alloc(char * class,char * subclass,char * pub,int flag)52 sysevent_alloc(char *class, char *subclass, char *pub, int flag)
53 {
54 struct sysevent *ev;
55
56 ASSERT(class != NULL);
57 ASSERT(subclass != NULL);
58 ASSERT(pub != NULL);
59 ASSERT(flag == SE_SLEEP);
60
61 ev = kmem_alloc(sizeof(*ev), KM_SLEEP);
62 ev->se_nvl = NULL;
63 strlcpy(ev->se_class, class, sizeof(ev->se_class));
64 strlcpy(ev->se_subclass, subclass, sizeof(ev->se_subclass));
65 strlcpy(ev->se_pub, pub, sizeof(ev->se_pub));
66
67 return ((sysevent_t *)ev);
68 }
69
70 void
sysevent_free(sysevent_t * evp)71 sysevent_free(sysevent_t *evp)
72 {
73 struct sysevent *ev = (struct sysevent *)evp;
74
75 ASSERT(evp != NULL);
76
77 if (ev->se_nvl != NULL)
78 sysevent_free_attr(ev->se_nvl);
79 kmem_free(ev, sizeof(*ev));
80 }
81
82 int
sysevent_add_attr(sysevent_attr_list_t ** ev_attr_list,char * name,sysevent_value_t * se_value,int flag)83 sysevent_add_attr(sysevent_attr_list_t **ev_attr_list, char *name,
84 sysevent_value_t *se_value, int flag)
85 {
86 nvlist_t *nvl;
87 int error;
88
89 ASSERT(ev_attr_list != NULL);
90 ASSERT(name != NULL);
91 ASSERT(se_value != NULL);
92 ASSERT(flag == SE_SLEEP);
93
94 if (strlen(name) >= MAX_ATTR_NAME)
95 return (SE_EINVAL);
96
97 nvl = *ev_attr_list;
98 if (nvl == NULL) {
99 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, KM_SLEEP) != 0)
100 return (SE_ENOMEM);
101 }
102
103 error = 0;
104
105 switch (se_value->value_type) {
106 case SE_DATA_TYPE_UINT64:
107 error = nvlist_add_uint64(nvl, name, se_value->value.sv_uint64);
108 break;
109 case SE_DATA_TYPE_STRING:
110 if (strlen(se_value->value.sv_string) >= MAX_STRING_SZ)
111 error = SE_EINVAL;
112 if (error == 0) {
113 error = nvlist_add_string(nvl, name,
114 se_value->value.sv_string);
115 }
116 break;
117 default:
118 #if 0
119 printf("%s: type %d is not implemented\n", __func__,
120 se_value->value_type);
121 #endif
122 break;
123 }
124
125 if (error != 0) {
126 nvlist_free(nvl);
127 return (error);
128 }
129
130 *ev_attr_list = nvl;
131
132 return (0);
133 }
134
135 void
sysevent_free_attr(sysevent_attr_list_t * ev_attr_list)136 sysevent_free_attr(sysevent_attr_list_t *ev_attr_list)
137 {
138
139 nvlist_free(ev_attr_list);
140 }
141
142 int
sysevent_attach_attributes(sysevent_t * evp,sysevent_attr_list_t * ev_attr_list)143 sysevent_attach_attributes(sysevent_t *evp, sysevent_attr_list_t *ev_attr_list)
144 {
145 struct sysevent *ev = (struct sysevent *)evp;
146
147 ASSERT(ev->se_nvl == NULL);
148
149 ev->se_nvl = ev_attr_list;
150
151 return (0);
152 }
153
154 void
sysevent_detach_attributes(sysevent_t * evp)155 sysevent_detach_attributes(sysevent_t *evp)
156 {
157 struct sysevent *ev = (struct sysevent *)evp;
158
159 ASSERT(ev->se_nvl != NULL);
160
161 ev->se_nvl = NULL;
162 }
163
164 int
log_sysevent(sysevent_t * evp,int flag,sysevent_id_t * eid)165 log_sysevent(sysevent_t *evp, int flag, sysevent_id_t *eid)
166 {
167 #ifdef __NetBSD__
168 /* XXXNETBSD we ought to do something here */
169 #else
170 struct sysevent *ev = (struct sysevent *)evp;
171 struct sbuf *sb;
172 const char *type;
173 char typestr[128];
174 nvpair_t *elem = NULL;
175
176 ASSERT(evp != NULL);
177 ASSERT(ev->se_nvl != NULL);
178 ASSERT(flag == SE_SLEEP);
179 ASSERT(eid != NULL);
180
181 sb = sbuf_new_auto();
182 if (sb == NULL)
183 return (SE_ENOMEM);
184 type = NULL;
185
186 while ((elem = nvlist_next_nvpair(ev->se_nvl, elem)) != NULL) {
187 switch (nvpair_type(elem)) {
188 case DATA_TYPE_BOOLEAN:
189 {
190 boolean_t value;
191
192 (void) nvpair_value_boolean_value(elem, &value);
193 sbuf_printf(sb, " %s=%s", nvpair_name(elem),
194 value ? "true" : "false");
195 break;
196 }
197 case DATA_TYPE_UINT8:
198 {
199 uint8_t value;
200
201 (void) nvpair_value_uint8(elem, &value);
202 sbuf_printf(sb, " %s=%hhu", nvpair_name(elem), value);
203 break;
204 }
205 case DATA_TYPE_INT32:
206 {
207 int32_t value;
208
209 (void) nvpair_value_int32(elem, &value);
210 sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
211 (intmax_t)value);
212 break;
213 }
214 case DATA_TYPE_UINT32:
215 {
216 uint32_t value;
217
218 (void) nvpair_value_uint32(elem, &value);
219 sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
220 (uintmax_t)value);
221 break;
222 }
223 case DATA_TYPE_INT64:
224 {
225 int64_t value;
226
227 (void) nvpair_value_int64(elem, &value);
228 sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
229 (intmax_t)value);
230 break;
231 }
232 case DATA_TYPE_UINT64:
233 {
234 uint64_t value;
235
236 (void) nvpair_value_uint64(elem, &value);
237 sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
238 (uintmax_t)value);
239 break;
240 }
241 case DATA_TYPE_STRING:
242 {
243 char *value;
244
245 (void) nvpair_value_string(elem, &value);
246 sbuf_printf(sb, " %s=%s", nvpair_name(elem), value);
247 if (strcmp(FM_CLASS, nvpair_name(elem)) == 0)
248 type = value;
249 break;
250 }
251 case DATA_TYPE_UINT8_ARRAY:
252 {
253 uint8_t *value;
254 uint_t ii, nelem;
255
256 (void) nvpair_value_uint8_array(elem, &value, &nelem);
257 sbuf_printf(sb, " %s=", nvpair_name(elem));
258 for (ii = 0; ii < nelem; ii++)
259 sbuf_printf(sb, "%02hhx", value[ii]);
260 break;
261 }
262 case DATA_TYPE_UINT16_ARRAY:
263 {
264 uint16_t *value;
265 uint_t ii, nelem;
266
267 (void) nvpair_value_uint16_array(elem, &value, &nelem);
268 sbuf_printf(sb, " %s=", nvpair_name(elem));
269 for (ii = 0; ii < nelem; ii++)
270 sbuf_printf(sb, "%04hx", value[ii]);
271 break;
272 }
273 case DATA_TYPE_UINT32_ARRAY:
274 {
275 uint32_t *value;
276 uint_t ii, nelem;
277
278 (void) nvpair_value_uint32_array(elem, &value, &nelem);
279 sbuf_printf(sb, " %s=", nvpair_name(elem));
280 for (ii = 0; ii < nelem; ii++)
281 sbuf_printf(sb, "%08jx", (uintmax_t)value[ii]);
282 break;
283 }
284 case DATA_TYPE_UINT64_ARRAY:
285 {
286 uint64_t *value;
287 uint_t ii, nelem;
288
289 (void) nvpair_value_uint64_array(elem, &value, &nelem);
290 sbuf_printf(sb, " %s=", nvpair_name(elem));
291 for (ii = 0; ii < nelem; ii++)
292 sbuf_printf(sb, "%016jx", (uintmax_t)value[ii]);
293 break;
294 }
295 default:
296 #if 0
297 printf("%s: type %d is not implemented\n", __func__,
298 nvpair_type(elem));
299 #endif
300 break;
301 }
302 }
303
304 if (sbuf_finish(sb) != 0) {
305 sbuf_delete(sb);
306 return (SE_ENOMEM);
307 }
308
309 if (type == NULL)
310 type = ev->se_subclass;
311 if (strncmp(type, "ESC_ZFS_", 8) == 0) {
312 snprintf(typestr, sizeof(typestr), "misc.fs.zfs.%s", type + 8);
313 type = typestr;
314 }
315 devctl_notify("ZFS", "ZFS", type, sbuf_data(sb));
316 sbuf_delete(sb);
317 #endif
318
319 return (0);
320 }
321
322 int
_ddi_log_sysevent(char * vendor,char * class,char * subclass,nvlist_t * attr_list,sysevent_id_t * eidp,int flag)323 _ddi_log_sysevent(char *vendor, char *class, char *subclass,
324 nvlist_t *attr_list, sysevent_id_t *eidp, int flag)
325 {
326 sysevent_t *ev;
327 int ret;
328
329 ASSERT(vendor != NULL);
330 ASSERT(class != NULL);
331 ASSERT(subclass != NULL);
332 ASSERT(attr_list != NULL);
333 ASSERT(eidp != NULL);
334 ASSERT(flag == DDI_SLEEP);
335
336 ev = sysevent_alloc(class, subclass, vendor, SE_SLEEP);
337 ASSERT(ev != NULL);
338 (void)sysevent_attach_attributes(ev, attr_list);
339 ret = log_sysevent(ev, SE_SLEEP, eidp);
340 sysevent_detach_attributes(ev);
341 sysevent_free(ev);
342
343 return (ret);
344 }
345