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