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
44struct sysevent {
45	nvlist_t	*se_nvl;
46	char		 se_class[128];
47	char		 se_subclass[128];
48	char		 se_pub[128];
49};
50
51sysevent_t *
52sysevent_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
70void
71sysevent_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
82int
83sysevent_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
135void
136sysevent_free_attr(sysevent_attr_list_t *ev_attr_list)
137{
138
139	nvlist_free(ev_attr_list);
140}
141
142int
143sysevent_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
154void
155sysevent_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
164int
165log_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
322int
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