149b225e1SGavin Maltby /*
249b225e1SGavin Maltby * CDDL HEADER START
349b225e1SGavin Maltby *
449b225e1SGavin Maltby * The contents of this file are subject to the terms of the
549b225e1SGavin Maltby * Common Development and Distribution License (the "License").
649b225e1SGavin Maltby * You may not use this file except in compliance with the License.
749b225e1SGavin Maltby *
849b225e1SGavin Maltby * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
949b225e1SGavin Maltby * or http://www.opensolaris.org/os/licensing.
1049b225e1SGavin Maltby * See the License for the specific language governing permissions
1149b225e1SGavin Maltby * and limitations under the License.
1249b225e1SGavin Maltby *
1349b225e1SGavin Maltby * When distributing Covered Code, include this CDDL HEADER in each
1449b225e1SGavin Maltby * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1549b225e1SGavin Maltby * If applicable, add the following below this CDDL HEADER, with the
1649b225e1SGavin Maltby * fields enclosed by brackets "[]" replaced with your own identifying
1749b225e1SGavin Maltby * information: Portions Copyright [yyyy] [name of copyright owner]
1849b225e1SGavin Maltby *
1949b225e1SGavin Maltby * CDDL HEADER END
2049b225e1SGavin Maltby */
2149b225e1SGavin Maltby
2249b225e1SGavin Maltby /*
23*f6e214c7SGavin Maltby * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2449b225e1SGavin Maltby */
2549b225e1SGavin Maltby
2649b225e1SGavin Maltby /*
2749b225e1SGavin Maltby * Subscription event access interfaces.
2849b225e1SGavin Maltby */
2949b225e1SGavin Maltby
3049b225e1SGavin Maltby #include <sys/types.h>
3149b225e1SGavin Maltby #include <limits.h>
3249b225e1SGavin Maltby #include <atomic.h>
3349b225e1SGavin Maltby #include <libsysevent.h>
3449b225e1SGavin Maltby #include <umem.h>
3549b225e1SGavin Maltby #include <fm/libfmevent.h>
3649b225e1SGavin Maltby #include <sys/fm/protocol.h>
3749b225e1SGavin Maltby
3849b225e1SGavin Maltby #include "fmev_impl.h"
3949b225e1SGavin Maltby
40*f6e214c7SGavin Maltby #define FMEV_API_ENTER(iep, v) \
41*f6e214c7SGavin Maltby fmev_api_enter(fmev_shdl_cmn(((iep)->ei_hdl)), LIBFMEVENT_VERSION_##v)
4249b225e1SGavin Maltby
4349b225e1SGavin Maltby typedef struct {
4449b225e1SGavin Maltby uint32_t ei_magic; /* _FMEVMAGIC */
4549b225e1SGavin Maltby volatile uint32_t ei_refcnt; /* reference count */
4649b225e1SGavin Maltby fmev_shdl_t ei_hdl; /* handle received on */
4749b225e1SGavin Maltby nvlist_t *ei_nvl; /* (duped) sysevent attribute list */
4849b225e1SGavin Maltby uint64_t ei_fmtime[2]; /* embedded protocol event time */
4949b225e1SGavin Maltby } fmev_impl_t;
5049b225e1SGavin Maltby
5149b225e1SGavin Maltby #define FMEV2IMPL(ev) ((fmev_impl_t *)(ev))
5249b225e1SGavin Maltby #define IMPL2FMEV(iep) ((fmev_t)(iep))
5349b225e1SGavin Maltby
5449b225e1SGavin Maltby #define _FMEVMAGIC 0x466d4576 /* "FmEv" */
5549b225e1SGavin Maltby
5649b225e1SGavin Maltby #define EVENT_VALID(iep) ((iep)->ei_magic == _FMEVMAGIC && \
5749b225e1SGavin Maltby (iep)->ei_refcnt > 0 && fmev_shdl_valid((iep)->ei_hdl))
5849b225e1SGavin Maltby
5949b225e1SGavin Maltby #define FM_TIME_SEC 0
6049b225e1SGavin Maltby #define FM_TIME_NSEC 1
6149b225e1SGavin Maltby
6249b225e1SGavin Maltby /*
6349b225e1SGavin Maltby * Transform a received sysevent_t into an fmev_t.
6449b225e1SGavin Maltby */
6549b225e1SGavin Maltby
6649b225e1SGavin Maltby uint64_t fmev_bad_attr, fmev_bad_tod, fmev_bad_class;
6749b225e1SGavin Maltby
6849b225e1SGavin Maltby fmev_t
fmev_sysev2fmev(fmev_shdl_t hdl,sysevent_t * sep,char ** clsp,nvlist_t ** nvlp)6949b225e1SGavin Maltby fmev_sysev2fmev(fmev_shdl_t hdl, sysevent_t *sep, char **clsp, nvlist_t **nvlp)
7049b225e1SGavin Maltby {
7149b225e1SGavin Maltby fmev_impl_t *iep;
7249b225e1SGavin Maltby uint64_t *tod;
7349b225e1SGavin Maltby uint_t nelem;
7449b225e1SGavin Maltby
7549b225e1SGavin Maltby if ((iep = fmev_shdl_alloc(hdl, sizeof (*iep))) == NULL)
7649b225e1SGavin Maltby return (NULL);
7749b225e1SGavin Maltby
7849b225e1SGavin Maltby /*
7949b225e1SGavin Maltby * sysevent_get_attr_list duplicates the nvlist - we free it
8049b225e1SGavin Maltby * in fmev_free when the reference count hits zero.
8149b225e1SGavin Maltby */
8249b225e1SGavin Maltby if (sysevent_get_attr_list(sep, &iep->ei_nvl) != 0) {
8349b225e1SGavin Maltby fmev_shdl_free(hdl, iep, sizeof (*iep));
8449b225e1SGavin Maltby fmev_bad_attr++;
8549b225e1SGavin Maltby return (NULL);
8649b225e1SGavin Maltby }
8749b225e1SGavin Maltby
8849b225e1SGavin Maltby *nvlp = iep->ei_nvl;
8949b225e1SGavin Maltby
9049b225e1SGavin Maltby if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, clsp) != 0) {
9149b225e1SGavin Maltby nvlist_free(iep->ei_nvl);
9249b225e1SGavin Maltby fmev_shdl_free(hdl, iep, sizeof (*iep));
9349b225e1SGavin Maltby fmev_bad_class++;
9449b225e1SGavin Maltby return (NULL);
9549b225e1SGavin Maltby }
9649b225e1SGavin Maltby
9749b225e1SGavin Maltby if (nvlist_lookup_uint64_array(iep->ei_nvl, "__tod", &tod,
9849b225e1SGavin Maltby &nelem) != 0 || nelem != 2) {
9949b225e1SGavin Maltby nvlist_free(iep->ei_nvl);
10049b225e1SGavin Maltby fmev_shdl_free(hdl, iep, sizeof (*iep));
10149b225e1SGavin Maltby fmev_bad_tod++;
10249b225e1SGavin Maltby return (NULL);
10349b225e1SGavin Maltby }
10449b225e1SGavin Maltby
10549b225e1SGavin Maltby iep->ei_fmtime[FM_TIME_SEC] = tod[0];
10649b225e1SGavin Maltby iep->ei_fmtime[FM_TIME_NSEC] = tod[1];
10749b225e1SGavin Maltby
10849b225e1SGavin Maltby /*
10949b225e1SGavin Maltby * Now remove the fmd-private __tod and __ttl members.
11049b225e1SGavin Maltby */
11149b225e1SGavin Maltby (void) nvlist_remove_all(iep->ei_nvl, "__tod");
11249b225e1SGavin Maltby (void) nvlist_remove_all(iep->ei_nvl, "__ttl");
11349b225e1SGavin Maltby
11449b225e1SGavin Maltby iep->ei_magic = _FMEVMAGIC;
11549b225e1SGavin Maltby iep->ei_hdl = hdl;
11649b225e1SGavin Maltby iep->ei_refcnt = 1;
11749b225e1SGavin Maltby ASSERT(EVENT_VALID(iep));
11849b225e1SGavin Maltby
11949b225e1SGavin Maltby return (IMPL2FMEV(iep));
12049b225e1SGavin Maltby }
12149b225e1SGavin Maltby
12249b225e1SGavin Maltby static void
fmev_free(fmev_impl_t * iep)12349b225e1SGavin Maltby fmev_free(fmev_impl_t *iep)
12449b225e1SGavin Maltby {
12549b225e1SGavin Maltby ASSERT(iep->ei_refcnt == 0);
12649b225e1SGavin Maltby
12749b225e1SGavin Maltby nvlist_free(iep->ei_nvl);
12849b225e1SGavin Maltby fmev_shdl_free(iep->ei_hdl, iep, sizeof (*iep));
12949b225e1SGavin Maltby }
13049b225e1SGavin Maltby
13149b225e1SGavin Maltby void
fmev_hold(fmev_t ev)13249b225e1SGavin Maltby fmev_hold(fmev_t ev)
13349b225e1SGavin Maltby {
13449b225e1SGavin Maltby fmev_impl_t *iep = FMEV2IMPL(ev);
13549b225e1SGavin Maltby
13649b225e1SGavin Maltby ASSERT(EVENT_VALID(iep));
13749b225e1SGavin Maltby
138*f6e214c7SGavin Maltby (void) FMEV_API_ENTER(iep, 1);
13949b225e1SGavin Maltby
14049b225e1SGavin Maltby atomic_inc_32(&iep->ei_refcnt);
14149b225e1SGavin Maltby }
14249b225e1SGavin Maltby
14349b225e1SGavin Maltby void
fmev_rele(fmev_t ev)14449b225e1SGavin Maltby fmev_rele(fmev_t ev)
14549b225e1SGavin Maltby {
14649b225e1SGavin Maltby fmev_impl_t *iep = FMEV2IMPL(ev);
14749b225e1SGavin Maltby
14849b225e1SGavin Maltby ASSERT(EVENT_VALID(iep));
14949b225e1SGavin Maltby
150*f6e214c7SGavin Maltby (void) FMEV_API_ENTER(iep, 1);
15149b225e1SGavin Maltby
15249b225e1SGavin Maltby if (atomic_dec_32_nv(&iep->ei_refcnt) == 0)
15349b225e1SGavin Maltby fmev_free(iep);
15449b225e1SGavin Maltby }
15549b225e1SGavin Maltby
15649b225e1SGavin Maltby fmev_t
fmev_dup(fmev_t ev)15749b225e1SGavin Maltby fmev_dup(fmev_t ev)
15849b225e1SGavin Maltby {
15949b225e1SGavin Maltby fmev_impl_t *iep = FMEV2IMPL(ev);
16049b225e1SGavin Maltby fmev_impl_t *cp;
16149b225e1SGavin Maltby
16249b225e1SGavin Maltby ASSERT(EVENT_VALID(iep));
16349b225e1SGavin Maltby
164*f6e214c7SGavin Maltby if (!FMEV_API_ENTER(iep, 1))
165*f6e214c7SGavin Maltby return (NULL); /* fmev_errno set */
16649b225e1SGavin Maltby
16749b225e1SGavin Maltby if (ev == NULL) {
16849b225e1SGavin Maltby (void) fmev_seterr(FMEVERR_API);
16949b225e1SGavin Maltby return (NULL);
17049b225e1SGavin Maltby }
17149b225e1SGavin Maltby
17249b225e1SGavin Maltby if ((cp = fmev_shdl_alloc(iep->ei_hdl, sizeof (*iep))) == NULL) {
17349b225e1SGavin Maltby (void) fmev_seterr(FMEVERR_ALLOC);
17449b225e1SGavin Maltby return (NULL);
17549b225e1SGavin Maltby }
17649b225e1SGavin Maltby
17749b225e1SGavin Maltby if (nvlist_dup(iep->ei_nvl, &cp->ei_nvl, 0) != 0) {
17849b225e1SGavin Maltby fmev_shdl_free(iep->ei_hdl, cp, sizeof (*cp));
17949b225e1SGavin Maltby (void) fmev_seterr(FMEVERR_ALLOC);
18049b225e1SGavin Maltby return (NULL);
18149b225e1SGavin Maltby }
18249b225e1SGavin Maltby
18349b225e1SGavin Maltby cp->ei_magic = _FMEVMAGIC;
18449b225e1SGavin Maltby cp->ei_hdl = iep->ei_hdl;
18549b225e1SGavin Maltby cp->ei_refcnt = 1;
18649b225e1SGavin Maltby return (IMPL2FMEV(cp));
18749b225e1SGavin Maltby }
18849b225e1SGavin Maltby
18949b225e1SGavin Maltby nvlist_t *
fmev_attr_list(fmev_t ev)19049b225e1SGavin Maltby fmev_attr_list(fmev_t ev)
19149b225e1SGavin Maltby {
19249b225e1SGavin Maltby fmev_impl_t *iep = FMEV2IMPL(ev);
19349b225e1SGavin Maltby
19449b225e1SGavin Maltby ASSERT(EVENT_VALID(iep));
19549b225e1SGavin Maltby
196*f6e214c7SGavin Maltby if (!FMEV_API_ENTER(iep, 1))
197*f6e214c7SGavin Maltby return (NULL); /* fmev_errno set */
19849b225e1SGavin Maltby
19949b225e1SGavin Maltby if (ev == NULL) {
20049b225e1SGavin Maltby (void) fmev_seterr(FMEVERR_API);
20149b225e1SGavin Maltby return (NULL);
20249b225e1SGavin Maltby } else if (iep->ei_nvl == NULL) {
20349b225e1SGavin Maltby (void) fmev_seterr(FMEVERR_MALFORMED_EVENT);
20449b225e1SGavin Maltby return (NULL);
20549b225e1SGavin Maltby }
20649b225e1SGavin Maltby
20749b225e1SGavin Maltby return (iep->ei_nvl);
20849b225e1SGavin Maltby }
20949b225e1SGavin Maltby
21049b225e1SGavin Maltby const char *
fmev_class(fmev_t ev)21149b225e1SGavin Maltby fmev_class(fmev_t ev)
21249b225e1SGavin Maltby {
21349b225e1SGavin Maltby fmev_impl_t *iep = FMEV2IMPL(ev);
21449b225e1SGavin Maltby const char *class;
21549b225e1SGavin Maltby
21649b225e1SGavin Maltby ASSERT(EVENT_VALID(iep));
21749b225e1SGavin Maltby
218*f6e214c7SGavin Maltby if (!FMEV_API_ENTER(iep, 1))
219*f6e214c7SGavin Maltby return (NULL); /* fmev_errno set */
22049b225e1SGavin Maltby
22149b225e1SGavin Maltby if (ev == NULL) {
22249b225e1SGavin Maltby (void) fmev_seterr(FMEVERR_API);
22349b225e1SGavin Maltby return ("");
22449b225e1SGavin Maltby }
22549b225e1SGavin Maltby
22649b225e1SGavin Maltby if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, (char **)&class) != 0 ||
22749b225e1SGavin Maltby *class == '\0') {
22849b225e1SGavin Maltby (void) fmev_seterr(FMEVERR_MALFORMED_EVENT);
22949b225e1SGavin Maltby return ("");
23049b225e1SGavin Maltby }
23149b225e1SGavin Maltby
23249b225e1SGavin Maltby return (class);
23349b225e1SGavin Maltby }
23449b225e1SGavin Maltby
23549b225e1SGavin Maltby fmev_err_t
fmev_timespec(fmev_t ev,struct timespec * tp)23649b225e1SGavin Maltby fmev_timespec(fmev_t ev, struct timespec *tp)
23749b225e1SGavin Maltby {
23849b225e1SGavin Maltby fmev_impl_t *iep = FMEV2IMPL(ev);
23949b225e1SGavin Maltby uint64_t timetlimit;
24049b225e1SGavin Maltby
24149b225e1SGavin Maltby ASSERT(EVENT_VALID(iep));
242*f6e214c7SGavin Maltby if (!FMEV_API_ENTER(iep, 1))
243*f6e214c7SGavin Maltby return (fmev_errno);
24449b225e1SGavin Maltby
24549b225e1SGavin Maltby #ifdef _LP64
24649b225e1SGavin Maltby timetlimit = INT64_MAX;
24749b225e1SGavin Maltby #else
24849b225e1SGavin Maltby timetlimit = INT32_MAX;
24949b225e1SGavin Maltby #endif
25049b225e1SGavin Maltby
25149b225e1SGavin Maltby if (iep->ei_fmtime[FM_TIME_SEC] > timetlimit)
25249b225e1SGavin Maltby return (FMEVERR_OVERFLOW);
25349b225e1SGavin Maltby
25449b225e1SGavin Maltby tp->tv_sec = (time_t)iep->ei_fmtime[FM_TIME_SEC];
25549b225e1SGavin Maltby tp->tv_nsec = (long)iep->ei_fmtime[FM_TIME_NSEC];
25649b225e1SGavin Maltby
25749b225e1SGavin Maltby return (FMEV_SUCCESS);
25849b225e1SGavin Maltby }
25949b225e1SGavin Maltby
26049b225e1SGavin Maltby uint64_t
fmev_time_sec(fmev_t ev)26149b225e1SGavin Maltby fmev_time_sec(fmev_t ev)
26249b225e1SGavin Maltby {
26349b225e1SGavin Maltby return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_SEC]);
26449b225e1SGavin Maltby }
26549b225e1SGavin Maltby
26649b225e1SGavin Maltby uint64_t
fmev_time_nsec(fmev_t ev)26749b225e1SGavin Maltby fmev_time_nsec(fmev_t ev)
26849b225e1SGavin Maltby {
26949b225e1SGavin Maltby return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_NSEC]);
27049b225e1SGavin Maltby }
27149b225e1SGavin Maltby
27249b225e1SGavin Maltby struct tm *
fmev_localtime(fmev_t ev,struct tm * tm)27349b225e1SGavin Maltby fmev_localtime(fmev_t ev, struct tm *tm)
27449b225e1SGavin Maltby {
27549b225e1SGavin Maltby time_t seconds;
27649b225e1SGavin Maltby
27749b225e1SGavin Maltby seconds = (time_t)fmev_time_sec(ev);
27849b225e1SGavin Maltby return (localtime_r(&seconds, tm));
27949b225e1SGavin Maltby }
280*f6e214c7SGavin Maltby
281*f6e214c7SGavin Maltby fmev_shdl_t
fmev_ev2shdl(fmev_t ev)282*f6e214c7SGavin Maltby fmev_ev2shdl(fmev_t ev)
283*f6e214c7SGavin Maltby {
284*f6e214c7SGavin Maltby fmev_impl_t *iep = FMEV2IMPL(ev);
285*f6e214c7SGavin Maltby
286*f6e214c7SGavin Maltby if (!FMEV_API_ENTER(iep, 2))
287*f6e214c7SGavin Maltby return (NULL);
288*f6e214c7SGavin Maltby
289*f6e214c7SGavin Maltby return (iep->ei_hdl);
290*f6e214c7SGavin Maltby }
291