1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Subscription event access interfaces. 28 */ 29 30 #include <sys/types.h> 31 #include <limits.h> 32 #include <atomic.h> 33 #include <libsysevent.h> 34 #include <umem.h> 35 #include <fm/libfmevent.h> 36 #include <sys/fm/protocol.h> 37 38 #include "fmev_impl.h" 39 40 #define FMEV_API_ENTER(iep, v) \ 41 fmev_api_enter(fmev_shdl_cmn(((iep)->ei_hdl)), LIBFMEVENT_VERSION_##v) 42 43 typedef struct { 44 uint32_t ei_magic; /* _FMEVMAGIC */ 45 volatile uint32_t ei_refcnt; /* reference count */ 46 fmev_shdl_t ei_hdl; /* handle received on */ 47 nvlist_t *ei_nvl; /* (duped) sysevent attribute list */ 48 uint64_t ei_fmtime[2]; /* embedded protocol event time */ 49 } fmev_impl_t; 50 51 #define FMEV2IMPL(ev) ((fmev_impl_t *)(ev)) 52 #define IMPL2FMEV(iep) ((fmev_t)(iep)) 53 54 #define _FMEVMAGIC 0x466d4576 /* "FmEv" */ 55 56 #define EVENT_VALID(iep) ((iep)->ei_magic == _FMEVMAGIC && \ 57 (iep)->ei_refcnt > 0 && fmev_shdl_valid((iep)->ei_hdl)) 58 59 #define FM_TIME_SEC 0 60 #define FM_TIME_NSEC 1 61 62 /* 63 * Transform a received sysevent_t into an fmev_t. 64 */ 65 66 uint64_t fmev_bad_attr, fmev_bad_tod, fmev_bad_class; 67 68 fmev_t 69 fmev_sysev2fmev(fmev_shdl_t hdl, sysevent_t *sep, char **clsp, nvlist_t **nvlp) 70 { 71 fmev_impl_t *iep; 72 uint64_t *tod; 73 uint_t nelem; 74 75 if ((iep = fmev_shdl_alloc(hdl, sizeof (*iep))) == NULL) 76 return (NULL); 77 78 /* 79 * sysevent_get_attr_list duplicates the nvlist - we free it 80 * in fmev_free when the reference count hits zero. 81 */ 82 if (sysevent_get_attr_list(sep, &iep->ei_nvl) != 0) { 83 fmev_shdl_free(hdl, iep, sizeof (*iep)); 84 fmev_bad_attr++; 85 return (NULL); 86 } 87 88 *nvlp = iep->ei_nvl; 89 90 if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, clsp) != 0) { 91 nvlist_free(iep->ei_nvl); 92 fmev_shdl_free(hdl, iep, sizeof (*iep)); 93 fmev_bad_class++; 94 return (NULL); 95 } 96 97 if (nvlist_lookup_uint64_array(iep->ei_nvl, "__tod", &tod, 98 &nelem) != 0 || nelem != 2) { 99 nvlist_free(iep->ei_nvl); 100 fmev_shdl_free(hdl, iep, sizeof (*iep)); 101 fmev_bad_tod++; 102 return (NULL); 103 } 104 105 iep->ei_fmtime[FM_TIME_SEC] = tod[0]; 106 iep->ei_fmtime[FM_TIME_NSEC] = tod[1]; 107 108 /* 109 * Now remove the fmd-private __tod and __ttl members. 110 */ 111 (void) nvlist_remove_all(iep->ei_nvl, "__tod"); 112 (void) nvlist_remove_all(iep->ei_nvl, "__ttl"); 113 114 iep->ei_magic = _FMEVMAGIC; 115 iep->ei_hdl = hdl; 116 iep->ei_refcnt = 1; 117 ASSERT(EVENT_VALID(iep)); 118 119 return (IMPL2FMEV(iep)); 120 } 121 122 static void 123 fmev_free(fmev_impl_t *iep) 124 { 125 ASSERT(iep->ei_refcnt == 0); 126 127 nvlist_free(iep->ei_nvl); 128 fmev_shdl_free(iep->ei_hdl, iep, sizeof (*iep)); 129 } 130 131 void 132 fmev_hold(fmev_t ev) 133 { 134 fmev_impl_t *iep = FMEV2IMPL(ev); 135 136 ASSERT(EVENT_VALID(iep)); 137 138 (void) FMEV_API_ENTER(iep, 1); 139 140 atomic_inc_32(&iep->ei_refcnt); 141 } 142 143 void 144 fmev_rele(fmev_t ev) 145 { 146 fmev_impl_t *iep = FMEV2IMPL(ev); 147 148 ASSERT(EVENT_VALID(iep)); 149 150 (void) FMEV_API_ENTER(iep, 1); 151 152 if (atomic_dec_32_nv(&iep->ei_refcnt) == 0) 153 fmev_free(iep); 154 } 155 156 fmev_t 157 fmev_dup(fmev_t ev) 158 { 159 fmev_impl_t *iep = FMEV2IMPL(ev); 160 fmev_impl_t *cp; 161 162 ASSERT(EVENT_VALID(iep)); 163 164 if (!FMEV_API_ENTER(iep, 1)) 165 return (NULL); /* fmev_errno set */ 166 167 if (ev == NULL) { 168 (void) fmev_seterr(FMEVERR_API); 169 return (NULL); 170 } 171 172 if ((cp = fmev_shdl_alloc(iep->ei_hdl, sizeof (*iep))) == NULL) { 173 (void) fmev_seterr(FMEVERR_ALLOC); 174 return (NULL); 175 } 176 177 if (nvlist_dup(iep->ei_nvl, &cp->ei_nvl, 0) != 0) { 178 fmev_shdl_free(iep->ei_hdl, cp, sizeof (*cp)); 179 (void) fmev_seterr(FMEVERR_ALLOC); 180 return (NULL); 181 } 182 183 cp->ei_magic = _FMEVMAGIC; 184 cp->ei_hdl = iep->ei_hdl; 185 cp->ei_refcnt = 1; 186 return (IMPL2FMEV(cp)); 187 } 188 189 nvlist_t * 190 fmev_attr_list(fmev_t ev) 191 { 192 fmev_impl_t *iep = FMEV2IMPL(ev); 193 194 ASSERT(EVENT_VALID(iep)); 195 196 if (!FMEV_API_ENTER(iep, 1)) 197 return (NULL); /* fmev_errno set */ 198 199 if (ev == NULL) { 200 (void) fmev_seterr(FMEVERR_API); 201 return (NULL); 202 } else if (iep->ei_nvl == NULL) { 203 (void) fmev_seterr(FMEVERR_MALFORMED_EVENT); 204 return (NULL); 205 } 206 207 return (iep->ei_nvl); 208 } 209 210 const char * 211 fmev_class(fmev_t ev) 212 { 213 fmev_impl_t *iep = FMEV2IMPL(ev); 214 const char *class; 215 216 ASSERT(EVENT_VALID(iep)); 217 218 if (!FMEV_API_ENTER(iep, 1)) 219 return (NULL); /* fmev_errno set */ 220 221 if (ev == NULL) { 222 (void) fmev_seterr(FMEVERR_API); 223 return (""); 224 } 225 226 if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, (char **)&class) != 0 || 227 *class == '\0') { 228 (void) fmev_seterr(FMEVERR_MALFORMED_EVENT); 229 return (""); 230 } 231 232 return (class); 233 } 234 235 fmev_err_t 236 fmev_timespec(fmev_t ev, struct timespec *tp) 237 { 238 fmev_impl_t *iep = FMEV2IMPL(ev); 239 uint64_t timetlimit; 240 241 ASSERT(EVENT_VALID(iep)); 242 if (!FMEV_API_ENTER(iep, 1)) 243 return (fmev_errno); 244 245 #ifdef _LP64 246 timetlimit = INT64_MAX; 247 #else 248 timetlimit = INT32_MAX; 249 #endif 250 251 if (iep->ei_fmtime[FM_TIME_SEC] > timetlimit) 252 return (FMEVERR_OVERFLOW); 253 254 tp->tv_sec = (time_t)iep->ei_fmtime[FM_TIME_SEC]; 255 tp->tv_nsec = (long)iep->ei_fmtime[FM_TIME_NSEC]; 256 257 return (FMEV_SUCCESS); 258 } 259 260 uint64_t 261 fmev_time_sec(fmev_t ev) 262 { 263 return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_SEC]); 264 } 265 266 uint64_t 267 fmev_time_nsec(fmev_t ev) 268 { 269 return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_NSEC]); 270 } 271 272 struct tm * 273 fmev_localtime(fmev_t ev, struct tm *tm) 274 { 275 time_t seconds; 276 277 seconds = (time_t)fmev_time_sec(ev); 278 return (localtime_r(&seconds, tm)); 279 } 280 281 fmev_shdl_t 282 fmev_ev2shdl(fmev_t ev) 283 { 284 fmev_impl_t *iep = FMEV2IMPL(ev); 285 286 if (!FMEV_API_ENTER(iep, 2)) 287 return (NULL); 288 289 return (iep->ei_hdl); 290 } 291