xref: /NextBSD/sys/cddl/compat/opensolaris/kern/opensolaris_sysevent.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
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$");
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 
42 struct sysevent {
43 	nvlist_t	*se_nvl;
44 	char		 se_class[128];
45 	char		 se_subclass[128];
46 	char		 se_pub[128];
47 };
48 
49 sysevent_t *
sysevent_alloc(char * class,char * subclass,char * pub,int flag)50 sysevent_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 
68 void
sysevent_free(sysevent_t * evp)69 sysevent_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 
80 int
sysevent_add_attr(sysevent_attr_list_t ** ev_attr_list,char * name,sysevent_value_t * se_value,int flag)81 sysevent_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 #if 0
117 		printf("%s: type %d is not implemented\n", __func__,
118 		    se_value->value_type);
119 #endif
120 		break;
121 	}
122 
123 	if (error != 0) {
124 		nvlist_free(nvl);
125 		return (error);
126 	}
127 
128 	*ev_attr_list = nvl;
129 
130 	return (0);
131 }
132 
133 void
sysevent_free_attr(sysevent_attr_list_t * ev_attr_list)134 sysevent_free_attr(sysevent_attr_list_t *ev_attr_list)
135 {
136 
137 	nvlist_free(ev_attr_list);
138 }
139 
140 int
sysevent_attach_attributes(sysevent_t * evp,sysevent_attr_list_t * ev_attr_list)141 sysevent_attach_attributes(sysevent_t *evp, sysevent_attr_list_t *ev_attr_list)
142 {
143 	struct sysevent *ev = (struct sysevent *)evp;
144 
145 	ASSERT(ev->se_nvl == NULL);
146 
147 	ev->se_nvl = ev_attr_list;
148 
149 	return (0);
150 }
151 
152 void
sysevent_detach_attributes(sysevent_t * evp)153 sysevent_detach_attributes(sysevent_t *evp)
154 {
155 	struct sysevent *ev = (struct sysevent *)evp;
156 
157 	ASSERT(ev->se_nvl != NULL);
158 
159 	ev->se_nvl = NULL;
160 }
161 
162 int
log_sysevent(sysevent_t * evp,int flag,sysevent_id_t * eid)163 log_sysevent(sysevent_t *evp, int flag, sysevent_id_t *eid)
164 {
165 	struct sysevent *ev = (struct sysevent *)evp;
166 	struct sbuf *sb;
167 	const char *type;
168 	char typestr[128];
169 	nvpair_t *elem = NULL;
170 
171 	ASSERT(evp != NULL);
172 	ASSERT(ev->se_nvl != NULL);
173 	ASSERT(flag == SE_SLEEP);
174 	ASSERT(eid != NULL);
175 
176 	sb = sbuf_new_auto();
177 	if (sb == NULL)
178 		return (SE_ENOMEM);
179 	type = NULL;
180 
181 	while ((elem = nvlist_next_nvpair(ev->se_nvl, elem)) != NULL) {
182 		switch (nvpair_type(elem)) {
183 		case DATA_TYPE_BOOLEAN:
184 		    {
185 			boolean_t value;
186 
187 			(void) nvpair_value_boolean_value(elem, &value);
188 			sbuf_printf(sb, " %s=%s", nvpair_name(elem),
189 			    value ? "true" : "false");
190 			break;
191 		    }
192 		case DATA_TYPE_UINT8:
193 		    {
194 			uint8_t value;
195 
196 			(void) nvpair_value_uint8(elem, &value);
197 			sbuf_printf(sb, " %s=%hhu", nvpair_name(elem), value);
198 			break;
199 		    }
200 		case DATA_TYPE_INT32:
201 		    {
202 			int32_t value;
203 
204 			(void) nvpair_value_int32(elem, &value);
205 			sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
206 			    (intmax_t)value);
207 			break;
208 		    }
209 		case DATA_TYPE_UINT32:
210 		    {
211 			uint32_t value;
212 
213 			(void) nvpair_value_uint32(elem, &value);
214 			sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
215 			    (uintmax_t)value);
216 			break;
217 		    }
218 		case DATA_TYPE_INT64:
219 		    {
220 			int64_t value;
221 
222 			(void) nvpair_value_int64(elem, &value);
223 			sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
224 			    (intmax_t)value);
225 			break;
226 		    }
227 		case DATA_TYPE_UINT64:
228 		    {
229 			uint64_t value;
230 
231 			(void) nvpair_value_uint64(elem, &value);
232 			sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
233 			    (uintmax_t)value);
234 			break;
235 		    }
236 		case DATA_TYPE_STRING:
237 		    {
238 			char *value;
239 
240 			(void) nvpair_value_string(elem, &value);
241 			sbuf_printf(sb, " %s=%s", nvpair_name(elem), value);
242 			if (strcmp(FM_CLASS, nvpair_name(elem)) == 0)
243 				type = value;
244 			break;
245 		    }
246 		case DATA_TYPE_UINT8_ARRAY:
247 		    {
248 		    	uint8_t *value;
249 			uint_t ii, nelem;
250 
251 			(void) nvpair_value_uint8_array(elem, &value, &nelem);
252 			sbuf_printf(sb, " %s=", nvpair_name(elem));
253 			for (ii = 0; ii < nelem; ii++)
254 				sbuf_printf(sb, "%02hhx", value[ii]);
255 			break;
256 		    }
257 		case DATA_TYPE_UINT16_ARRAY:
258 		    {
259 		    	uint16_t *value;
260 			uint_t ii, nelem;
261 
262 			(void) nvpair_value_uint16_array(elem, &value, &nelem);
263 			sbuf_printf(sb, " %s=", nvpair_name(elem));
264 			for (ii = 0; ii < nelem; ii++)
265 				sbuf_printf(sb, "%04hx", value[ii]);
266 			break;
267 		    }
268 		case DATA_TYPE_UINT32_ARRAY:
269 		    {
270 		    	uint32_t *value;
271 			uint_t ii, nelem;
272 
273 			(void) nvpair_value_uint32_array(elem, &value, &nelem);
274 			sbuf_printf(sb, " %s=", nvpair_name(elem));
275 			for (ii = 0; ii < nelem; ii++)
276 				sbuf_printf(sb, "%08jx", (uintmax_t)value[ii]);
277 			break;
278 		    }
279 		case DATA_TYPE_UINT64_ARRAY:
280 		    {
281 		    	uint64_t *value;
282 			uint_t ii, nelem;
283 
284 			(void) nvpair_value_uint64_array(elem, &value, &nelem);
285 			sbuf_printf(sb, " %s=", nvpair_name(elem));
286 			for (ii = 0; ii < nelem; ii++)
287 				sbuf_printf(sb, "%016jx", (uintmax_t)value[ii]);
288 			break;
289 		    }
290 		default:
291 #if 0
292 			printf("%s: type %d is not implemented\n", __func__,
293 			    nvpair_type(elem));
294 #endif
295 			break;
296 		}
297 	}
298 
299 	if (sbuf_finish(sb) != 0) {
300 		sbuf_delete(sb);
301 		return (SE_ENOMEM);
302 	}
303 
304 	if (type == NULL)
305 		type = ev->se_subclass;
306 	if (strncmp(type, "ESC_ZFS_", 8) == 0) {
307 		snprintf(typestr, sizeof(typestr), "misc.fs.zfs.%s", type + 8);
308 		type = typestr;
309 	}
310 	devctl_notify("ZFS", "ZFS", type, sbuf_data(sb));
311 	sbuf_delete(sb);
312 
313 	return (0);
314 }
315 
316 int
_ddi_log_sysevent(char * vendor,char * class,char * subclass,nvlist_t * attr_list,sysevent_id_t * eidp,int flag)317 _ddi_log_sysevent(char *vendor, char *class, char *subclass,
318     nvlist_t *attr_list, sysevent_id_t *eidp, int flag)
319 {
320 	sysevent_t *ev;
321 	int ret;
322 
323 	ASSERT(vendor != NULL);
324 	ASSERT(class != NULL);
325 	ASSERT(subclass != NULL);
326 	ASSERT(attr_list != NULL);
327 	ASSERT(eidp != NULL);
328 	ASSERT(flag == DDI_SLEEP);
329 
330 	ev = sysevent_alloc(class, subclass, vendor, SE_SLEEP);
331 	ASSERT(ev != NULL);
332 	(void)sysevent_attach_attributes(ev, attr_list);
333         ret = log_sysevent(ev, SE_SLEEP, eidp);
334 	sysevent_detach_attributes(ev);
335 	sysevent_free(ev);
336 
337 	return (ret);
338 }
339