opensolaris_sysevent.c revision 219089
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__FBSDID("$FreeBSD: head/sys/cddl/compat/opensolaris/kern/opensolaris_sysevent.c 219089 2011-02-27 19:41:40Z pjd $");
29
30#include <sys/param.h>
31#include <sys/kernel.h>
32#include <sys/systm.h>
33#include <sys/malloc.h>
34#include <sys/kmem.h>
35#include <sys/sbuf.h>
36#include <sys/bus.h>
37#include <sys/nvpair.h>
38#include <sys/sunddi.h>
39#include <sys/sysevent.h>
40#include <sys/fm/protocol.h>
41
42struct sysevent {
43	nvlist_t	*se_nvl;
44	char		 se_class[128];
45	char		 se_subclass[128];
46	char		 se_pub[128];
47};
48
49sysevent_t *
50sysevent_alloc(char *class, char *subclass, char *pub, int flag)
51{
52	struct sysevent *ev;
53
54	ASSERT(class != NULL);
55	ASSERT(subclass != NULL);
56	ASSERT(pub != NULL);
57	ASSERT(flag == SE_SLEEP);
58
59	ev = kmem_alloc(sizeof(*ev), KM_SLEEP);
60	ev->se_nvl = NULL;
61	strlcpy(ev->se_class, class, sizeof(ev->se_class));
62	strlcpy(ev->se_subclass, subclass, sizeof(ev->se_subclass));
63	strlcpy(ev->se_pub, pub, sizeof(ev->se_pub));
64
65	return ((sysevent_t *)ev);
66}
67
68void
69sysevent_free(sysevent_t *evp)
70{
71	struct sysevent *ev = (struct sysevent *)evp;
72
73	ASSERT(evp != NULL);
74
75	if (ev->se_nvl != NULL)
76		sysevent_free_attr(ev->se_nvl);
77	kmem_free(ev, sizeof(*ev));
78}
79
80int
81sysevent_add_attr(sysevent_attr_list_t **ev_attr_list, char *name,
82    sysevent_value_t *se_value, int flag)
83{
84	nvlist_t *nvl;
85	int error;
86
87	ASSERT(ev_attr_list != NULL);
88	ASSERT(name != NULL);
89	ASSERT(se_value != NULL);
90	ASSERT(flag == SE_SLEEP);
91
92	if (strlen(name) >= MAX_ATTR_NAME)
93		return (SE_EINVAL);
94
95	nvl = *ev_attr_list;
96	if (nvl == NULL) {
97		if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, KM_SLEEP) != 0)
98			return (SE_ENOMEM);
99	}
100
101	error = 0;
102
103	switch (se_value->value_type) {
104	case SE_DATA_TYPE_UINT64:
105		error = nvlist_add_uint64(nvl, name, se_value->value.sv_uint64);
106		break;
107	case SE_DATA_TYPE_STRING:
108		if (strlen(se_value->value.sv_string) >= MAX_STRING_SZ)
109			error = SE_EINVAL;
110		if (error == 0) {
111			error = nvlist_add_string(nvl, name,
112			    se_value->value.sv_string);
113		}
114		break;
115	default:
116		printf("%s: type %d is not implemented\n", __func__,
117		    se_value->value_type);
118		break;
119	}
120
121	if (error != 0) {
122		nvlist_free(nvl);
123		return (error);
124	}
125
126	*ev_attr_list = nvl;
127
128	return (0);
129}
130
131void
132sysevent_free_attr(sysevent_attr_list_t *ev_attr_list)
133{
134
135	nvlist_free(ev_attr_list);
136}
137
138int
139sysevent_attach_attributes(sysevent_t *evp, sysevent_attr_list_t *ev_attr_list)
140{
141	struct sysevent *ev = (struct sysevent *)evp;
142
143	ASSERT(ev->se_nvl == NULL);
144
145	ev->se_nvl = ev_attr_list;
146
147	return (0);
148}
149
150void
151sysevent_detach_attributes(sysevent_t *evp)
152{
153	struct sysevent *ev = (struct sysevent *)evp;
154
155	ASSERT(ev->se_nvl != NULL);
156
157	ev->se_nvl = NULL;
158}
159
160int
161log_sysevent(sysevent_t *evp, int flag, sysevent_id_t *eid)
162{
163	struct sysevent *ev = (struct sysevent *)evp;
164	struct sbuf *sb;
165	const char *type;
166	char typestr[128];
167	nvpair_t *elem = NULL;
168
169	ASSERT(evp != NULL);
170	ASSERT(ev->se_nvl != NULL);
171	ASSERT(flag == SE_SLEEP);
172	ASSERT(eid != NULL);
173
174	sb = sbuf_new_auto();
175	if (sb == NULL)
176		return (SE_ENOMEM);
177	type = NULL;
178
179	while ((elem = nvlist_next_nvpair(ev->se_nvl, elem)) != NULL) {
180		switch (nvpair_type(elem)) {
181		case DATA_TYPE_BOOLEAN:
182		    {
183			boolean_t value;
184
185			(void) nvpair_value_boolean_value(elem, &value);
186			sbuf_printf(sb, " %s=%s", nvpair_name(elem),
187			    value ? "true" : "false");
188			break;
189		    }
190		case DATA_TYPE_UINT8:
191		    {
192			uint8_t value;
193
194			(void) nvpair_value_uint8(elem, &value);
195			sbuf_printf(sb, " %s=%hhu", nvpair_name(elem), value);
196			break;
197		    }
198		case DATA_TYPE_INT32:
199		    {
200			int32_t value;
201
202			(void) nvpair_value_int32(elem, &value);
203			sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
204			    (intmax_t)value);
205			break;
206		    }
207		case DATA_TYPE_UINT32:
208		    {
209			uint32_t value;
210
211			(void) nvpair_value_uint32(elem, &value);
212			sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
213			    (uintmax_t)value);
214			break;
215		    }
216		case DATA_TYPE_INT64:
217		    {
218			int64_t value;
219
220			(void) nvpair_value_int64(elem, &value);
221			sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
222			    (intmax_t)value);
223			break;
224		    }
225		case DATA_TYPE_UINT64:
226		    {
227			uint64_t value;
228
229			(void) nvpair_value_uint64(elem, &value);
230			sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
231			    (uintmax_t)value);
232			break;
233		    }
234		case DATA_TYPE_STRING:
235		    {
236			char *value;
237
238			(void) nvpair_value_string(elem, &value);
239			sbuf_printf(sb, " %s=%s", nvpair_name(elem), value);
240			if (strcmp(FM_CLASS, nvpair_name(elem)) == 0)
241				type = value;
242			break;
243		    }
244		case DATA_TYPE_UINT8_ARRAY:
245		    {
246		    	uint8_t *value;
247			uint_t ii, nelem;
248
249			(void) nvpair_value_uint8_array(elem, &value, &nelem);
250			sbuf_printf(sb, " %s=", nvpair_name(elem));
251			for (ii = 0; ii < nelem; ii++)
252				sbuf_printf(sb, "%02hhx", value[ii]);
253			break;
254		    }
255		case DATA_TYPE_UINT16_ARRAY:
256		    {
257		    	uint16_t *value;
258			uint_t ii, nelem;
259
260			(void) nvpair_value_uint16_array(elem, &value, &nelem);
261			sbuf_printf(sb, " %s=", nvpair_name(elem));
262			for (ii = 0; ii < nelem; ii++)
263				sbuf_printf(sb, "%04hx", value[ii]);
264			break;
265		    }
266		case DATA_TYPE_UINT32_ARRAY:
267		    {
268		    	uint32_t *value;
269			uint_t ii, nelem;
270
271			(void) nvpair_value_uint32_array(elem, &value, &nelem);
272			sbuf_printf(sb, " %s=", nvpair_name(elem));
273			for (ii = 0; ii < nelem; ii++)
274				sbuf_printf(sb, "%08jx", (uintmax_t)value[ii]);
275			break;
276		    }
277		case DATA_TYPE_UINT64_ARRAY:
278		    {
279		    	uint64_t *value;
280			uint_t ii, nelem;
281
282			(void) nvpair_value_uint64_array(elem, &value, &nelem);
283			sbuf_printf(sb, " %s=", nvpair_name(elem));
284			for (ii = 0; ii < nelem; ii++)
285				sbuf_printf(sb, "%016jx", (uintmax_t)value[ii]);
286			break;
287		    }
288		default:
289			printf("%s: type %d is not implemented\n", __func__,
290			    nvpair_type(elem));
291			break;
292		}
293	}
294
295	if (sbuf_finish(sb) != 0) {
296		sbuf_delete(sb);
297		return (SE_ENOMEM);
298	}
299
300	if (type == NULL)
301		type = ev->se_subclass;
302	if (strncmp(type, "ESC_ZFS_", 8) == 0) {
303		snprintf(typestr, sizeof(typestr), "misc.fs.zfs.%s", type + 8);
304		type = typestr;
305	}
306	devctl_notify("ZFS", "ZFS", type, sbuf_data(sb));
307	sbuf_delete(sb);
308
309	return (0);
310}
311
312int
313_ddi_log_sysevent(char *vendor, char *class, char *subclass,
314    nvlist_t *attr_list, sysevent_id_t *eidp, int flag)
315{
316	sysevent_t *ev;
317	int ret;
318
319	ASSERT(vendor != NULL);
320	ASSERT(class != NULL);
321	ASSERT(subclass != NULL);
322	ASSERT(attr_list != NULL);
323	ASSERT(eidp != NULL);
324	ASSERT(flag == DDI_SLEEP);
325
326	ev = sysevent_alloc(class, subclass, vendor, SE_SLEEP);
327	ASSERT(ev != NULL);
328	(void)sysevent_attach_attributes(ev, attr_list);
329        ret = log_sysevent(ev, SE_SLEEP, eidp);
330	sysevent_detach_attributes(ev);
331	sysevent_free(ev);
332
333	return (ret);
334}
335