xref: /netbsd-src/external/cddl/osnet/sys/kern/sysevent.c (revision ba2539a9805a0544ff82c0003cc02fe1eee5603d)
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