summaryrefslogtreecommitdiff
path: root/usr/src/lib/fm/libfmevent/common/libfmevent.h
blob: a90343b34c1b7fe8902abb80c71897cb64e44c23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
/*
 * 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(7) 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 */