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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Subscription event access interfaces. 29 */ 30 31 #include <sys/types.h> 32 #include <limits.h> 33 #include <atomic.h> 34 #include <libsysevent.h> 35 #include <umem.h> 36 #include <fm/libfmevent.h> 37 #include <sys/fm/protocol.h> 38 39 #include "fmev_impl.h" 40 41 #define API_ENTERV1(iep) \ 42 ((void) fmev_api_enter(fmev_shdl_cmn(((iep)->ei_hdl)), \ 43 LIBFMEVENT_VERSION_1)) 44 45 typedef struct { 46 uint32_t ei_magic; /* _FMEVMAGIC */ 47 volatile uint32_t ei_refcnt; /* reference count */ 48 fmev_shdl_t ei_hdl; /* handle received on */ 49 nvlist_t *ei_nvl; /* (duped) sysevent attribute list */ 50 uint64_t ei_fmtime[2]; /* embedded protocol event time */ 51 } fmev_impl_t; 52 53 #define FMEV2IMPL(ev) ((fmev_impl_t *)(ev)) 54 #define IMPL2FMEV(iep) ((fmev_t)(iep)) 55 56 #define _FMEVMAGIC 0x466d4576 /* "FmEv" */ 57 58 #define EVENT_VALID(iep) ((iep)->ei_magic == _FMEVMAGIC && \ 59 (iep)->ei_refcnt > 0 && fmev_shdl_valid((iep)->ei_hdl)) 60 61 #define FM_TIME_SEC 0 62 #define FM_TIME_NSEC 1 63 64 /* 65 * Transform a received sysevent_t into an fmev_t. 66 */ 67 68 uint64_t fmev_bad_attr, fmev_bad_tod, fmev_bad_class; 69 70 fmev_t 71 fmev_sysev2fmev(fmev_shdl_t hdl, sysevent_t *sep, char **clsp, nvlist_t **nvlp) 72 { 73 fmev_impl_t *iep; 74 uint64_t *tod; 75 uint_t nelem; 76 77 if ((iep = fmev_shdl_alloc(hdl, sizeof (*iep))) == NULL) 78 return (NULL); 79 80 /* 81 * sysevent_get_attr_list duplicates the nvlist - we free it 82 * in fmev_free when the reference count hits zero. 83 */ 84 if (sysevent_get_attr_list(sep, &iep->ei_nvl) != 0) { 85 fmev_shdl_free(hdl, iep, sizeof (*iep)); 86 fmev_bad_attr++; 87 return (NULL); 88 } 89 90 *nvlp = iep->ei_nvl; 91 92 if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, clsp) != 0) { 93 nvlist_free(iep->ei_nvl); 94 fmev_shdl_free(hdl, iep, sizeof (*iep)); 95 fmev_bad_class++; 96 return (NULL); 97 } 98 99 if (nvlist_lookup_uint64_array(iep->ei_nvl, "__tod", &tod, 100 &nelem) != 0 || nelem != 2) { 101 nvlist_free(iep->ei_nvl); 102 fmev_shdl_free(hdl, iep, sizeof (*iep)); 103 fmev_bad_tod++; 104 return (NULL); 105 } 106 107 iep->ei_fmtime[FM_TIME_SEC] = tod[0]; 108 iep->ei_fmtime[FM_TIME_NSEC] = tod[1]; 109 110 /* 111 * Now remove the fmd-private __tod and __ttl members. 112 */ 113 (void) nvlist_remove_all(iep->ei_nvl, "__tod"); 114 (void) nvlist_remove_all(iep->ei_nvl, "__ttl"); 115 116 iep->ei_magic = _FMEVMAGIC; 117 iep->ei_hdl = hdl; 118 iep->ei_refcnt = 1; 119 ASSERT(EVENT_VALID(iep)); 120 121 return (IMPL2FMEV(iep)); 122 } 123 124 static void 125 fmev_free(fmev_impl_t *iep) 126 { 127 ASSERT(iep->ei_refcnt == 0); 128 129 nvlist_free(iep->ei_nvl); 130 fmev_shdl_free(iep->ei_hdl, iep, sizeof (*iep)); 131 } 132 133 void 134 fmev_hold(fmev_t ev) 135 { 136 fmev_impl_t *iep = FMEV2IMPL(ev); 137 138 ASSERT(EVENT_VALID(iep)); 139 140 API_ENTERV1(iep); 141 142 atomic_inc_32(&iep->ei_refcnt); 143 } 144 145 void 146 fmev_rele(fmev_t ev) 147 { 148 fmev_impl_t *iep = FMEV2IMPL(ev); 149 150 ASSERT(EVENT_VALID(iep)); 151 152 API_ENTERV1(iep); 153 154 if (atomic_dec_32_nv(&iep->ei_refcnt) == 0) 155 fmev_free(iep); 156 } 157 158 fmev_t 159 fmev_dup(fmev_t ev) 160 { 161 fmev_impl_t *iep = FMEV2IMPL(ev); 162 fmev_impl_t *cp; 163 164 ASSERT(EVENT_VALID(iep)); 165 166 API_ENTERV1(iep); 167 168 if (ev == NULL) { 169 (void) fmev_seterr(FMEVERR_API); 170 return (NULL); 171 } 172 173 if ((cp = fmev_shdl_alloc(iep->ei_hdl, sizeof (*iep))) == NULL) { 174 (void) fmev_seterr(FMEVERR_ALLOC); 175 return (NULL); 176 } 177 178 if (nvlist_dup(iep->ei_nvl, &cp->ei_nvl, 0) != 0) { 179 fmev_shdl_free(iep->ei_hdl, cp, sizeof (*cp)); 180 (void) fmev_seterr(FMEVERR_ALLOC); 181 return (NULL); 182 } 183 184 cp->ei_magic = _FMEVMAGIC; 185 cp->ei_hdl = iep->ei_hdl; 186 cp->ei_refcnt = 1; 187 return (IMPL2FMEV(cp)); 188 } 189 190 nvlist_t * 191 fmev_attr_list(fmev_t ev) 192 { 193 fmev_impl_t *iep = FMEV2IMPL(ev); 194 195 ASSERT(EVENT_VALID(iep)); 196 197 API_ENTERV1(iep); 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 API_ENTERV1(iep); 219 220 if (ev == NULL) { 221 (void) fmev_seterr(FMEVERR_API); 222 return (""); 223 } 224 225 if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, (char **)&class) != 0 || 226 *class == '\0') { 227 (void) fmev_seterr(FMEVERR_MALFORMED_EVENT); 228 return (""); 229 } 230 231 return (class); 232 } 233 234 fmev_err_t 235 fmev_timespec(fmev_t ev, struct timespec *tp) 236 { 237 fmev_impl_t *iep = FMEV2IMPL(ev); 238 uint64_t timetlimit; 239 240 ASSERT(EVENT_VALID(iep)); 241 API_ENTERV1(iep); 242 243 #ifdef _LP64 244 timetlimit = INT64_MAX; 245 #else 246 timetlimit = INT32_MAX; 247 #endif 248 249 if (iep->ei_fmtime[FM_TIME_SEC] > timetlimit) 250 return (FMEVERR_OVERFLOW); 251 252 tp->tv_sec = (time_t)iep->ei_fmtime[FM_TIME_SEC]; 253 tp->tv_nsec = (long)iep->ei_fmtime[FM_TIME_NSEC]; 254 255 return (FMEV_SUCCESS); 256 } 257 258 uint64_t 259 fmev_time_sec(fmev_t ev) 260 { 261 return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_SEC]); 262 } 263 264 uint64_t 265 fmev_time_nsec(fmev_t ev) 266 { 267 return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_NSEC]); 268 } 269 270 struct tm * 271 fmev_localtime(fmev_t ev, struct tm *tm) 272 { 273 time_t seconds; 274 275 seconds = (time_t)fmev_time_sec(ev); 276 return (localtime_r(&seconds, tm)); 277 } 278