view usr/src/lib/fm/libfmevent/common/fmev_evaccess.c @ 12979:ab9ae749152f

PSARC/2009/617 Software Events Notification Parameters CLI PSARC/2009/618 snmp-notify: SNMP Notification Daemon for Software Events PSARC/2009/619 smtp-notify: Email Notification Daemon for Software Events PSARC/2010/225 fmd for non-global Solaris zones PSARC/2010/226 Solaris Instance UUID PSARC/2010/227 nvlist_nvflag(3NVPAIR) PSARC/2010/228 libfmevent additions PSARC/2010/257 sysevent_evc_setpropnvl and sysevent_evc_getpropnvl PSARC/2010/265 FMRI and FMA Event Stabilty, 'ireport' category 1 event class, and the 'sw' FMRI scheme PSARC/2010/278 FMA/SMF integration: instance state transitions PSARC/2010/279 Modelling panics within FMA PSARC/2010/290 logadm.conf upgrade 6392476 fmdump needs to pretty-print 6393375 userland ereport/ireport event generation interfaces 6445732 Add email notification agent for FMA and software events 6804168 RFE: Allow an efficient means to monitor SMF services status changes 6866661 scf_values_destroy(3SCF) will segfault if is passed NULL 6884709 Add snmp notification agent for FMA and software events 6884712 Add private interface to tap into libfmd_msg macro expansion capabilities 6897919 fmd to run in a non-global zone 6897937 fmd use of non-private doors is not safe 6900081 add a UUID to Solaris kernel image for use in crashdump identification 6914884 model panic events as a defect diagnosis in FMA 6944862 fmd_case_open_uuid, fmd_case_uuisresolved, fmd_nvl_create_defect 6944866 log legacy sysevents in fmd 6944867 enumerate svc scheme in topo 6944868 software-diagnosis and software-response fmd modules 6944870 model SMF maintenance state as a defect diagnosis in FMA 6944876 savecore runs in foreground for systems with zfs root and dedicated dump 6965796 Implement notification parameters for SMF state transitions and FMA events 6968287 SUN-FM-MIB.mib needs to be updated to reflect Oracle information 6972331 logadm.conf upgrade PSARC/2010/290
author Gavin Maltby <gavin.maltby@oracle.com>
date Fri, 30 Jul 2010 17:04:17 +1000
parents b91faef0c984
children
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 */

/*
 * Subscription event access interfaces.
 */

#include <sys/types.h>
#include <limits.h>
#include <atomic.h>
#include <libsysevent.h>
#include <umem.h>
#include <fm/libfmevent.h>
#include <sys/fm/protocol.h>

#include "fmev_impl.h"

#define	FMEV_API_ENTER(iep, v) \
	fmev_api_enter(fmev_shdl_cmn(((iep)->ei_hdl)), LIBFMEVENT_VERSION_##v)

typedef struct {
	uint32_t ei_magic;		/* _FMEVMAGIC */
	volatile uint32_t ei_refcnt;	/* reference count */
	fmev_shdl_t ei_hdl;		/* handle received on */
	nvlist_t *ei_nvl;		/* (duped) sysevent attribute list */
	uint64_t ei_fmtime[2];		/* embedded protocol event time */
} fmev_impl_t;

#define	FMEV2IMPL(ev)	((fmev_impl_t *)(ev))
#define	IMPL2FMEV(iep)	((fmev_t)(iep))

#define	_FMEVMAGIC	0x466d4576	/* "FmEv" */

#define	EVENT_VALID(iep) ((iep)->ei_magic == _FMEVMAGIC && \
	(iep)->ei_refcnt > 0 && fmev_shdl_valid((iep)->ei_hdl))

#define	FM_TIME_SEC	0
#define	FM_TIME_NSEC	1

/*
 * Transform a received sysevent_t into an fmev_t.
 */

uint64_t fmev_bad_attr, fmev_bad_tod, fmev_bad_class;

fmev_t
fmev_sysev2fmev(fmev_shdl_t hdl, sysevent_t *sep, char **clsp, nvlist_t **nvlp)
{
	fmev_impl_t *iep;
	uint64_t *tod;
	uint_t nelem;

	if ((iep = fmev_shdl_alloc(hdl, sizeof (*iep))) == NULL)
		return (NULL);

	/*
	 * sysevent_get_attr_list duplicates the nvlist - we free it
	 * in fmev_free when the reference count hits zero.
	 */
	if (sysevent_get_attr_list(sep, &iep->ei_nvl) != 0) {
		fmev_shdl_free(hdl, iep, sizeof (*iep));
		fmev_bad_attr++;
		return (NULL);
	}

	*nvlp = iep->ei_nvl;

	if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, clsp) != 0) {
		nvlist_free(iep->ei_nvl);
		fmev_shdl_free(hdl, iep, sizeof (*iep));
		fmev_bad_class++;
		return (NULL);
	}

	if (nvlist_lookup_uint64_array(iep->ei_nvl, "__tod", &tod,
	    &nelem) != 0 || nelem != 2) {
		nvlist_free(iep->ei_nvl);
		fmev_shdl_free(hdl, iep, sizeof (*iep));
		fmev_bad_tod++;
		return (NULL);
	}

	iep->ei_fmtime[FM_TIME_SEC] = tod[0];
	iep->ei_fmtime[FM_TIME_NSEC] = tod[1];

	/*
	 * Now remove the fmd-private __tod and __ttl members.
	 */
	(void) nvlist_remove_all(iep->ei_nvl, "__tod");
	(void) nvlist_remove_all(iep->ei_nvl, "__ttl");

	iep->ei_magic = _FMEVMAGIC;
	iep->ei_hdl = hdl;
	iep->ei_refcnt = 1;
	ASSERT(EVENT_VALID(iep));

	return (IMPL2FMEV(iep));
}

static void
fmev_free(fmev_impl_t *iep)
{
	ASSERT(iep->ei_refcnt == 0);

	nvlist_free(iep->ei_nvl);
	fmev_shdl_free(iep->ei_hdl, iep, sizeof (*iep));
}

void
fmev_hold(fmev_t ev)
{
	fmev_impl_t *iep = FMEV2IMPL(ev);

	ASSERT(EVENT_VALID(iep));

	(void) FMEV_API_ENTER(iep, 1);

	atomic_inc_32(&iep->ei_refcnt);
}

void
fmev_rele(fmev_t ev)
{
	fmev_impl_t *iep = FMEV2IMPL(ev);

	ASSERT(EVENT_VALID(iep));

	(void) FMEV_API_ENTER(iep, 1);

	if (atomic_dec_32_nv(&iep->ei_refcnt) == 0)
		fmev_free(iep);
}

fmev_t
fmev_dup(fmev_t ev)
{
	fmev_impl_t *iep = FMEV2IMPL(ev);
	fmev_impl_t *cp;

	ASSERT(EVENT_VALID(iep));

	if (!FMEV_API_ENTER(iep, 1))
		return (NULL);	/* fmev_errno set */

	if (ev == NULL) {
		(void) fmev_seterr(FMEVERR_API);
		return (NULL);
	}

	if ((cp = fmev_shdl_alloc(iep->ei_hdl, sizeof (*iep))) == NULL) {
		(void) fmev_seterr(FMEVERR_ALLOC);
		return (NULL);
	}

	if (nvlist_dup(iep->ei_nvl, &cp->ei_nvl, 0) != 0) {
		fmev_shdl_free(iep->ei_hdl, cp, sizeof (*cp));
		(void) fmev_seterr(FMEVERR_ALLOC);
		return (NULL);
	}

	cp->ei_magic = _FMEVMAGIC;
	cp->ei_hdl = iep->ei_hdl;
	cp->ei_refcnt = 1;
	return (IMPL2FMEV(cp));
}

nvlist_t *
fmev_attr_list(fmev_t ev)
{
	fmev_impl_t *iep = FMEV2IMPL(ev);

	ASSERT(EVENT_VALID(iep));

	if (!FMEV_API_ENTER(iep, 1))
		return (NULL);	/* fmev_errno set */

	if (ev == NULL) {
		(void) fmev_seterr(FMEVERR_API);
		return (NULL);
	} else if (iep->ei_nvl == NULL) {
		(void) fmev_seterr(FMEVERR_MALFORMED_EVENT);
		return (NULL);
	}

	return (iep->ei_nvl);
}

const char *
fmev_class(fmev_t ev)
{
	fmev_impl_t *iep = FMEV2IMPL(ev);
	const char *class;

	ASSERT(EVENT_VALID(iep));

	if (!FMEV_API_ENTER(iep, 1))
		return (NULL);	/* fmev_errno set */

	if (ev == NULL) {
		(void) fmev_seterr(FMEVERR_API);
		return ("");
	}

	if (nvlist_lookup_string(iep->ei_nvl, FM_CLASS, (char **)&class) != 0 ||
	    *class == '\0') {
		(void) fmev_seterr(FMEVERR_MALFORMED_EVENT);
		return ("");
	}

	return (class);
}

fmev_err_t
fmev_timespec(fmev_t ev, struct timespec *tp)
{
	fmev_impl_t *iep = FMEV2IMPL(ev);
	uint64_t timetlimit;

	ASSERT(EVENT_VALID(iep));
	if (!FMEV_API_ENTER(iep, 1))
		return (fmev_errno);

#ifdef	_LP64
	timetlimit = INT64_MAX;
#else
	timetlimit = INT32_MAX;
#endif

	if (iep->ei_fmtime[FM_TIME_SEC] > timetlimit)
		return (FMEVERR_OVERFLOW);

	tp->tv_sec = (time_t)iep->ei_fmtime[FM_TIME_SEC];
	tp->tv_nsec = (long)iep->ei_fmtime[FM_TIME_NSEC];

	return (FMEV_SUCCESS);
}

uint64_t
fmev_time_sec(fmev_t ev)
{
	return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_SEC]);
}

uint64_t
fmev_time_nsec(fmev_t ev)
{
	return (FMEV2IMPL(ev)->ei_fmtime[FM_TIME_NSEC]);
}

struct tm *
fmev_localtime(fmev_t ev, struct tm *tm)
{
	time_t seconds;

	seconds = (time_t)fmev_time_sec(ev);
	return (localtime_r(&seconds, tm));
}

fmev_shdl_t
fmev_ev2shdl(fmev_t ev)
{
	fmev_impl_t *iep = FMEV2IMPL(ev);

	if (!FMEV_API_ENTER(iep, 2))
		return (NULL);

	return (iep->ei_hdl);
}