view usr/src/lib/fm/libfmevent/common/libfmevent.h @ 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.
 */

#ifndef _LIBFMEVENT_H
#define	_LIBFMEVENT_H

/*
 * FMA event library.
 *
 * A. Protocol event subscription interfaces (Committed).
 * B. Raw event publication interfaces (Consolidation Private).
 */

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/types.h>
#include <libnvpair.h>
#include <stdlib.h>
#include <door.h>
#include <sys/time.h>
#include <sys/fm/protocol.h>

/*
 * Library ABI interface version.  Quote the version you are using
 * to fmev_shdl_init.  Only interfaces introduced in or prior to the
 * quoted version will be available.  Once introduced an interface
 * only ever changes compatibly.
 *
 *				Introduced in
 *	API Function		LIBFMEVENT_VERSION_*
 *	-----------------------	--------------------
 *	fmev_attr_list;		1
 *	fmev_class;		1
 *	fmev_dup;		1
 *	fmev_ev2shdl		2
 *	fmev_hold;		1
 *	fmev_localtime;		1
 *	fmev_rele;		1
 *	fmev_shdl_alloc;	1
 *	fmev_shdl_init;		1
 *	fmev_shdl_fini;		1
 *	fmev_shdl_free;		1
 *	fmev_shdl_getauthority	2
 *	fmev_shdl_nvl2str	2
 *	fmev_shdl_strdup	2
 *	fmev_shdl_strfree	2
 *	fmev_shdl_subscribe;	1
 *	fmev_shdl_unsubscribe;	1
 *	fmev_shdl_zalloc;	1
 *	fmev_shdlctl_serialize;	1
 *	fmev_shdlctl_sigmask;	1
 *	fmev_shdlctl_thrattr;	1
 *	fmev_shdlctl_thrcreate;	1
 *	fmev_shdlctl_thrsetup;	1
 *	fmev_strerror;		1
 *	fmev_timespec;		1
 *	fmev_time_nsec;		1
 *	fmev_time_sec;		1
 */

#define	LIBFMEVENT_VERSION_1	1
#define	LIBFMEVENT_VERSION_2	2

#define	LIBFMEVENT_VERSION_LATEST	LIBFMEVENT_VERSION_2

/*
 * Success and error return values.  The descriptive comment for each
 * FMEVERR_* becomes the string that is returned by fmev_strerror for that
 * error type.
 */
typedef enum {
    FMEV_SUCCESS = 0,
    FMEV_OK = FMEV_SUCCESS, /* alias for FMEV_SUCCESS */
    FMEVERR_UNKNOWN = 0xe000, /* Error details unknown */
    FMEVERR_VERSION_MISMATCH, /* Library ABI version incompatible with caller */
    FMEVERR_API, /* Library API usage violation */
    FMEVERR_ALLOC, /* Failed to allocate additional resources */
    FMEVERR_MALFORMED_EVENT, /* Event contents are inconsistent or corrupt */
    FMEVERR_OVERFLOW, /* Operation would overflow result type */
    FMEVERR_INTERNAL, /* Internal library error */
    FMEVERR_NOPRIV, /* Insufficient permissions or privilege */
    FMEVERR_BUSY, /* Resource is busy */
    FMEVERR_DUPLICATE, /* Duplicate request */
    FMEVERR_BADCLASS, /* Bad event class or class pattern */
    FMEVERR_NOMATCH, /* No match to criteria provided */
    FMEVERR_MAX_SUBSCRIBERS, /* Exceeds maximum subscribers per handle */
    FMEVERR_INVALIDARG, /* Argument is invalid */
    FMEVERR_STRING2BIG, /* String argument exceeds maximum length */
    FMEVERR_VARARGS_MALFORMED, /* Varargs list bad or incorrectly terminated */
    FMEVERR_VARARGS_TOOLONG, /* Varargs list exceeds maximum length */
    FMEVERR_BADRULESET, /* Ruleset selected for publication is bad */
    FMEVERR_BADPRI, /* Priority selected for publication is bad */
    FMEVERR_TRANSPORT, /* Error in underlying event transport implementation */
    FMEVERR_NVLIST /* nvlist argument is not of type NV_UNIQUE_NAME */
} fmev_err_t;

/*
 * Some interfaces return an fmev_err_t - FMEV_SUCCESS on success, otherwise
 * failure of the indicated type.  You can use fmev_strerror to render an
 * fmev_err_t into a string.
 *
 * Other interfaces do not return an fmev_err_t directly.  For example
 * where we return a pointer an error is indicated by a NULL return.
 * In these cases you can retrieve the fmev_err_t describing the reason
 * for the failure using fmev_errno or get a string with
 * fmev_strerr(fmev_errno).  Note that fmev_errno is per-thread and holds
 * the error value for any error that occured during the last libfmevent
 * API call made by the current thread.  Use fmev_errno as you would
 * regular errno, but you should not assign to fmev_errno.
 */
extern const fmev_err_t *__fmev_errno(void);	/* do not use this directly */
#define	fmev_errno (*(__fmev_errno()))
extern const char *fmev_strerror(fmev_err_t);

/*
 * Part A - Protocol Event Subscription
 * ======
 *
 * Subscribe to FMA protocol events published by the fault management
 * daemon, receiving a callback for each matching event.
 *
 * This is a Committed interface (see attributes(5) for a definition).
 */

/*
 * Opaque subscription handle and event types.
 */
typedef struct fmev_shdl *fmev_shdl_t;
typedef struct fmev *fmev_t;

/*
 * Subscription callback function type for fmev_shdl_subscribe.
 */
typedef void fmev_cbfunc_t(fmev_t, const char *, nvlist_t *, void *);

/*
 * Initialize a new handle using fmev_shdl_init and quoting interface
 * version number along with alloc, zalloc and free function pointers (all
 * NULL to use the defaults.
 *
 * Close the handle and release resources with fmev_shdl_fini.
 */

extern fmev_shdl_t fmev_shdl_init(uint32_t,
    void *(*)(size_t),		/* alloc */
    void *(*)(size_t),		/* zalloc */
    void (*)(void *, size_t));	/* free */

extern fmev_err_t fmev_shdl_fini(fmev_shdl_t);

/*
 * Having created a handle you may optionally configure various properties
 * for this handle using fmev_shdlctl_*.  In most cases accepting the defaults
 * (that are obtained through fmev_shdl_init alone) will provide adequate
 * semantics - the controls below are provided for applications
 * that require fine-grained control over event delivery semantics and, in
 * particular, the service threads used to perform delivery callbacks.
 *
 * These controls may only be applied to a subscription handle
 * that has no current subscriptions in place.  You therefore cannot
 * change the properties once subscriptions are established, and the
 * handle properties apply uniformly to all subscriptions on that handle.
 * If you require different properties per subscription then use multiple
 * handles.
 *
 * fmev_shdlctl_serialize() will serialize all callbacks arising from all
 * subscriptions on a handle.  Event deliveries are normally single-threaded
 * on a per-subscribtion bases, that is a call to fmev_shdl_subscribe
 * will have deliveries arising from that subscription delivered
 * in a serialized fashion on a single thread dedicated to the subscription.
 * If multiple subscriptions are established then each has a dedicated
 * delivery thread - fmev_shdlctl_serialize arranges that only one of these
 * threads services a callback at any one time.
 *
 * fmev_shdlctl_thrattr() allows you to provide thread attributes for use
 * in pthread_create() when server threads are created.  The attributes
 * are not copied - the pthread_attr_t object passed must exist for
 * the duration of all subscriptions on the handle.  These attributes only
 * apply if fmev_shdlctl_thrcreate() is not in use on this handle.
 *
 * fmev_shdlctl_sigmask() allows you to provide a sigset_t signal mask
 * of signals to block in server threads.  The pthread_sigmask is set
 * to this immediately before pthread_create, and restored immediately
 * after pthread_create.  This mask only applies if fmev_shdlctl_thrcreate()
 * is not in use on this handle.
 *
 * fmev_shdlctl_thrsetup() allows you to install a custom door server thread
 * setup function - see door_xcreate(3C).  This will be used with the
 * default thread creation semantics or with any custom thread creation
 * function appointed with fmev_shdlctl_thrcreate().
 *
 * fmev_shdlctl_thrcreate() allows you to install a custom door server thread
 * creation function - see door_xcreate(3C).  This option excludes
 * fmev_shdlctl_{thrattr,sigmask} but the remaining options
 * of fmev_shdlctl_{serialize,thrsetup} are still available.
 */

extern fmev_err_t fmev_shdlctl_serialize(fmev_shdl_t);
extern fmev_err_t fmev_shdlctl_thrattr(fmev_shdl_t, pthread_attr_t *);
extern fmev_err_t fmev_shdlctl_sigmask(fmev_shdl_t, sigset_t *);
extern fmev_err_t fmev_shdlctl_thrsetup(fmev_shdl_t,
    door_xcreate_thrsetup_func_t *, void *);
extern fmev_err_t fmev_shdlctl_thrcreate(fmev_shdl_t,
    door_xcreate_server_func_t *, void *);

/*
 * Specify subscription choices on a handle using fmev_shdl_subscribe as
 * many times as needed to describe the full event set.  The event class
 * pattern can be wildcarded using simple '*' wildcarding.  When an event
 * matching a subscription is received a callback is performed to the
 * nominated function passing a fmev_t handle on the event and the
 * requested cookie argument.
 *
 * See the fault management event protocol specification for a description
 * of event classes.
 *
 * Drop a subscription using fmev_shdl_unsubscribe (which must match an
 * earlier subscription).
 */

#define	FMEV_MAX_CLASS	64	/* Longest class string for subscription */

extern fmev_err_t fmev_shdl_subscribe(fmev_shdl_t, const char *, fmev_cbfunc_t,
    void *);
extern fmev_err_t fmev_shdl_unsubscribe(fmev_shdl_t, const char *);

/*
 * Retrieve an authority nvlist for the fault manager that is forwarding
 * events to us.  This may be NULL if the fault manager has not yet
 * started up and made the information available.  The caller is
 * responsible for freeing the nvlist returned.
 */
extern fmev_err_t fmev_shdl_getauthority(fmev_shdl_t, nvlist_t **);

/*
 * Event access.  In the common case that the event is processed to
 * completion in the context of the event callback you need only
 * use fmev_attr_list to access the nvlist of event attributes,
 * with no responsibility for freeing the event or the nvlist; for
 * convenience, fmev_class and fmev_timestamp can both be used to
 * look inside an event without having to work with the attribute list (and
 * the callback receives the class as an argument).
 *
 * See libnvpair(3LIB) for interfaces to access an nvlist_t.
 *
 * The remaining interfaces apply in the case that event handling will
 * continue beyond the context of the event callback in which it is received.
 *
 * The fmev_t handle received in a callback is reference-counted;
 * the initial reference count on entry to the callback is 1, and the
 * count is always decremented when the callback completes.  To continue
 * to operate on a received event outside of the context of the callback
 * in which it is first received, take an fmev_hold during the callback
 * and later fmev_rele to release your hold (and free the event if the count
 * drops to 0).
 *
 * To access attributes of an event use fmev_attr_list to receive
 * an nvlist_t pointer valid for the same lifetime as the event itself (i.e.,
 * until its reference count drops to zero).
 *
 * If changes are made to a received fmev_t (discouraged) then all who
 * have a hold on the event share the change.  To obtain an independent
 * copy of an fmev_t, with a reference count of 1, use fmev_dup.  When
 * finished with the copy decrement the reference count
 * using fmev_rele - the event will be freed if the count reaches 0.
 *
 * For convenience you can retrieve the class of an event using fmev_class
 * (it's also available as an argument to a callback, and within the
 * event attribute list).  The string returned by fmev_class is valid for
 * the same lifetime as the event itself.
 *
 * The time at which a protocol event was generated is available via
 * fmev_timespec; tv_sec has seconds since the epoch, and tv_nsec nanoseconds
 * past that second.  This can fail with FMEVERR_OVERFLOW if the seconds
 * value does not fit within a time_t;  you can retrieve the 64-bit second
 * and nanosecond values with fmev_time_sec and fmev_time_nsec.
 *
 * An FMRI in an event payload is typically in nvlist form, i.e
 * DATA_TYPE_NVLIST.  That form is useful for extracting individual
 * component fields, but that requires knowledge of the FMRI scheme and
 * Public commitment thereof.  FMRIs are typically Private, but in some
 * cases they can be descriptive such as in listing the ASRU(s) affected
 * by a fault; so we offer an API member which will blindly render any
 * FMRI in its string form.  Use fmev_shdl_nvl2str to format an nvlist_t
 * as a string (if it is recognized as an FMRI); the caller is responsible
 * for freeing the returned string using fmev_shdl_strfree.  If
 * fmev_shdl_nvl2str fails it will return NULL with fmev_errno set -
 * FMEVERR_INVALIDARG if the nvlist_t does not appear to be a valid/known FMRI,
 * FMEVERR_ALLOC if an allocation for memory for the string failed.
 *
 * fmev_ev2shdl will return the fmev_shdl_t with which a received fmev_t
 * is associated.  It should only be used in an event delivery callback
 * context and for the event received in that callback.
 */

extern nvlist_t *fmev_attr_list(fmev_t);
extern const char *fmev_class(fmev_t);

extern fmev_err_t fmev_timespec(fmev_t, struct timespec *);
extern uint64_t fmev_time_sec(fmev_t);
extern uint64_t fmev_time_nsec(fmev_t);
extern struct tm *fmev_localtime(fmev_t, struct tm *);

extern void fmev_hold(fmev_t);
extern void fmev_rele(fmev_t);
extern fmev_t fmev_dup(fmev_t);

extern char *fmev_shdl_nvl2str(fmev_shdl_t, nvlist_t *);

extern fmev_shdl_t fmev_ev2shdl(fmev_t);

/*
 * The following will allocate and free memory based on the choices made
 * at fmev_shdl_init.
 */
void *fmev_shdl_alloc(fmev_shdl_t, size_t);
void *fmev_shdl_zalloc(fmev_shdl_t, size_t);
void fmev_shdl_free(fmev_shdl_t, void *, size_t);
extern char *fmev_shdl_strdup(fmev_shdl_t, char *);
extern void fmev_shdl_strfree(fmev_shdl_t, char *);

/*
 * Part B - Raw Event Publication
 * ======
 *
 * The following interfaces are private to the Solaris system and are
 * subject to change at any time without notice.  Applications using
 * these interfaces will fail to run on future releases.  The interfaces
 * should not be used for any purpose until they are publicly documented
 * for use outside of Sun.  These interface are *certain* to change
 * incompatibly, as the current interface is very much purpose-built for
 * a limited application.
 *
 * The interfaces below allow a process to publish a "raw" event
 * which will be transmitted to the fault manager and post-processed
 * into a full FMA protocol event.  The post-processing to be applied
 * is selected by a "ruleset" specified either implicitly or explicitly
 * at publication.  A ruleset will take the raw event (comprising
 * class, subclass, priority, raw payload) and mark it up into a full
 * protocol event; it may also augment the payload through looking up
 * details that would have been costly to compute at publication time.
 *
 * In this first implementation event dispatch is synchronous and blocking,
 * and not guaranteed to be re-entrant.  This limits the call sites
 * at which publication calls can be placed, and also means that careful
 * thought is required before sprinkling event publication code throughout
 * common system libraries.  The dispatch mechanism amounts to some
 * nvlist chicanery followed by a sysevent_evc_publish.  A future revision
 * will relax the context from which one may publish, and add more-powerful
 * publication interfaces.
 *
 * Some publication interfaces (those ending in _nvl) accept a preconstructed
 * nvlist as raw event payload.  We require that such an nvlist be of type
 * NV_UNIQUE_NAME.  The publication interfaces all call nvlist_free on any
 * nvlist that is passed for publication.
 *
 * Other publication interfaces allow you to build up the raw event payload
 * by specifying the members in a varargs list terminated by FMEV_ARG_TERM.
 * Again we require that payload member names are unique (that is, you cannot
 * have two members with the same name but different datatype).  See
 * <sys/nvpair.h> for the data_type_t enumeration of types supported - but
 * note that DATA_TYPE_BOOLEAN is excluded (DATA_TYPE_BOOLEAN_VALUE is
 * supported).  A single-valued (non-array type) member is specified with 3
 * consecutive varargs as:
 *
 *	(char *)name, DATA_TYPE_foo, (type)value
 *
 * An array-valued member is specified with 4 consecutive varargs as:
 *
 *	(char *)name, DATA_TYPE_foo_ARRAY, (int)nelem, (type *)arrayptr
 *
 * The varargs list that specifies the nvlist must begin with an
 * integer that specifies the number of members that follow.  For example:
 *
 * uint32_t mode;
 * char *clientname;
 * uint32_t ins[NARGS];
 *
 * fmev_publish("class", "subclass", FMEV_LOPRI,
 *	3,
 *	"mode", DATA_TYPE_UINT32, mode,
 *	"client", DATA_TYPE_STRING, clientname,
 *	"ins", DATA_TYPE_UINT32_ARRAY, sizeof (ins) / sizeof (ins[0]), ins,
 *	FMEV_ARG_TERM);
 *
 * The following tables summarize the capabilities of the various
 * publication interfaces.
 *
 *					     Detector
 * Interface			Ruleset? File/Line Func
 * ---------------------------- -------- --------- ----
 * fmev_publish_nvl		default	 Yes	   No
 * fmev_publish_nvl (C99)	default  Yes	   Yes
 * fmev_rspublish_nvl		chosen	 Yes	   No
 * fmev_rspublish_nvl (C99)	chosen	 Yes	   Yes
 * fmev_publish			default	 No	   No
 * fmev_publish (C99)		default	 Yes	   Yes
 * fmev_rspublish		chosen	 No	   No
 * fmev_rspublish (C99)		chosen	 Yes	   Yes
 *
 * Summary: if not using C99 then try to use the _nvl variants as the
 * varargs variants will not include file, line or function in the
 * detector.
 */

/*
 * In publishing an event you must select a "ruleset" (or accept the
 * defaults).  Rulesets are listed in the following header.
 */
#include <fm/libfmevent_ruleset.h>

/*
 * In publishing an event we can specify a class and subclass (which
 * in post-processing combine in some way selected by the ruleset to
 * form a full event protocol class).  The maximum class and subclass
 * string lengths are as follows.
 */
#define	FMEV_PUB_MAXCLASSLEN	32
#define	FMEV_PUB_MAXSUBCLASSLEN	32

/*
 * Events are either high-priority (try really hard not to lose) or
 * low-priority (can drop, throttle etc).  Convert a fmev_pri_t to
 * a string with fmev_pri_string().
 */
typedef enum fmev_pri {
	FMEV_LOPRI = 0x1000,
	FMEV_HIPRI
} fmev_pri_t;

extern const char *fmev_pri_string(fmev_pri_t);

/*
 * The varargs event publication interfaces must terminate the list
 * of nvpair specifications with FMEV_ARG_TERM.  This is to guard
 * against very easily-made mistakes in those arg lists.
 */
#define	FMEV_ARG_TERM	(void *)0xa4a3a2a1

/*
 * The following are NOT for direct use.
 */
extern fmev_err_t _i_fmev_publish_nvl(
    const char *, const char *, int64_t,
    const char *, const char *, const char *,
    fmev_pri_t, nvlist_t *);

extern fmev_err_t _i_fmev_publish(
    const char *, const char *, int64_t,
    const char *, const char *, const char *,
    fmev_pri_t,
    uint_t, ...);

/*
 * Post-processing will always generate a "detector" payload member.  In
 * the case of the _nvl publishing variants the detector information
 * includes file and line number, and - if your application is compiled
 * with C99 enabled - function name.
 */
#if __STDC_VERSION__ - 0 >= 199901L
#define	_FMEVFUNC	__func__
#else
#define	_FMEVFUNC	NULL
#endif

/*
 * All these definitions "return" an fmev_err_t.
 *
 * In the _nvl variants you pass a preconstructed event payload; otherwise
 * you include an integer indicating the number of payload
 * (name, type, value) tuples that follow, then all those tuples, finally
 * terminated by FMEV_ARG_TERM.
 *
 * In the rspublish variants you select a ruleset from
 * libfmevent_ruleset.h - just use the final suffix (as in
 * DEFAULT, EREPORT, ISV).
 *
 * The primary classification must not be NULL or the empty string.
 *
 *	arg	type		Description
 *	------- --------------- -------------------------------------------
 *	ruleset	const char *	Ruleset; can be NULL (implies default ruleset)
 *	cl1	const char *	Primary classification string
 *	cl2	const char *	Secondary classification string
 *	pri	fmev_pri_t	Priority
 *	nvl	nvlist_t *	Preconstructed attributes; caller must free
 *	ntuples	int		Number of tuples before FMEV_ARG_TERM
 *	suffix	-		See above.
 */

/*
 * fmev_publish_nvl - Default ruleset implied; class/subclass, pri and an nvl
 */
#define	fmev_publish_nvl(cl1, cl2, pri, nvl) \
	_i_fmev_publish_nvl( \
	    __FILE__, _FMEVFUNC, __LINE__, \
	    FMEV_RULESET_DEFAULT, cl1, cl2, \
	    pri, nvl)

/*
 * fmev_rspublish_nvl - As fmev_publish_nvl, but with a chosen ruleset.
 */
#define	fmev_rspublish_nvl(ruleset, cl1, cl2, pri, nvl) \
	_i_fmev_publish_nvl( \
	    __FILE__, _FMEVFUNC, __LINE__, \
	    ruleset, cl1, cl2, \
	    pri, nvl)

#if __STDC_VERSION__ - 0 >= 199901L && !defined(__lint)

/*
 * fmev_publish (C99 version) - Default ruleset; class/subclass, pri, nvpairs
 */
#define	fmev_publish(cl1, cl2, pri, ntuples, ...) \
	_i_fmev_publish( \
	    __FILE__, __func__, __LINE__, \
	    FMEV_RULESET_DEFAULT, cl1, cl2, \
	    pri, \
	    ntuples, __VA_ARGS__)


/*
 * fmev_rspublish (C99 version) - As fmev_publish, but with a chosen ruleset.
 */
#define	fmev_rspublish(ruleset, cl1, cl2, pri, ntuples, ...) \
	_i_fmev_publish( \
	    __FILE__, __func__, __LINE__, \
	    ruleset, cl1, cl2, \
	    pri, \
	    ntuples, __VA_ARGS__)

#else

/*
 * fmev_publish (pre C99)
 */
extern fmev_err_t fmev_publish(const char *, const char *,
    fmev_pri_t, uint_t, ...);

/*
 * fmev_rspublish (pre C99)
 */
extern fmev_err_t fmev_rspublish(const char *, const char *, const char *,
    fmev_pri_t, uint_t, ...);

#endif /* __STDC_VERSION__ */

#ifdef __cplusplus
}
#endif

#endif /* _LIBFMEVENT_H */