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