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 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#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 133void 134sysevent_free_attr(sysevent_attr_list_t *ev_attr_list) 135{ 136 137 nvlist_free(ev_attr_list); 138} 139 140int 141sysevent_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 152void 153sysevent_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 162int 163log_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 316int 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