NAME
	Subscription to fault management events from an external process

	fmev_shdl_init, fmev_shdl_fini,
	fmev_shdl_subscribe, fmev_shdl_unsubscribe,
	fmev_errno, fmev_strerror,
	fmev_attr_list, fmev_class,
	fmev_timespec, fmev_time_sec, fmev_time_nsec, fmev_localtime,
	fmev_hold, fmev_rele, fmev_dup,
	fmev_shdl_alloc, fmev_shdl_zalloc, fmev_shdl_free
	fmev_shdlctl_thrmin, fmev_shdlctl_thrmax, fmev_shdlctl_serialize,
	fmev_shdlctl_thrattr, fmev_shdlctl_sigmask, fmev_shdlctl_thrsetup,
	fmev_shdlctl_thrcreate

SYNOPSIS
	cc [flag ...] file ... -L/usr/lib/fm -lfmevent -lnvpair [library ...]

	#include <fm/libfmevent.h>
	#include <libnvpair.h>

	typedef enum fmev_err_t;
	extern fmev_err_t fmev_errno;
	const char *fmev_strerror(fmev_err_t err);

	typedef struct fmev_shdl *fmev_shdl_t;

	typedef void fmev_cbfunc_t(fmev_t, const char *, nvlist_t *, void *);

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

	fmev_err_t fmev_shdl_fini(fmev_shdl_t hdl);
	
	fmev_err_t fmev_shdl_subscribe(fmev_shdl_t hdl, const char *classpat,
	    fmev_cbfunc_t callback, void *cookie);

	fmev_err_t fmev_shdl_unsubscribe(fmev_shdl_t hdl, const char *classpat);

	fmev_err_t fmev_shdlctl_thrmin(fmev_shdl_t, uint32_t);

	fmev_err_t fmev_shdlctl_thrmax(fmev_shdl_t, uint32_t);

	fmev_err_t fmev_shdlctl_serialize(fmev_shdl_t);

	fmev_err_t fmev_shdlctl_thrattr(fmev_shdl_t, pthread_attr_t *);

	fmev_err_t fmev_shdlctl_sigmask(fmev_shdl_t, sigset_t *);

	fmev_err_t fmev_shdlctl_thrsetup(fmev_shdl_t,
    	    door_xcreate_thrsetup_func_t *, void *);

	fmev_err_t fmev_shdlctl_thrcreate(fmev_shdl_t,
    	    door_xcreate_server_func_t *, void *);

	typedef struct fmev *fmev_t;

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

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

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

	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);


DESCRIPTION
	The Solaris fault management daemon (fmd) is the central point
	in Solaris for fault management.  It receives fault management
	protocol events from various sources and publishes additional
	protocol events such as to describe a diagnosis it has arrived
	at or a subsequent repair event.  The event protocol is specified
	in the Sun Fault Management Event Protocol Specification.  The
	interfaces described here allow an external process to subscribe
	to protocol events.  See the Fault Management Daemon Programmer's
	Reference Guide for additonal information on fmd.

	The fmd module API (not a Committed interface) allows plugin modules
	to load within the fmd process, subscribe to events of interest,
	and participate in various diagnosis and response activities.
	Of those modules, some are notification agents and will subscribe
	to events describing diagnoses and their subsequent lifecycle
	and render these to console/syslog (for the syslog-msgs agent)
	and via SNMP trap and browsable MIB (for the snmp-trapgen module
	and the corresponding dlmod for the SNMP daemon).  It has not
	been possible to subscribe to protocol events outside of the
	context of an fmd plugin.  The libfmevent interface provides this
	external subscription mechanism.  External subscribers may receive
	protocol events as fmd modules do, but they cannot participate in
	other aspects of the fmd module API such as diagnosis.  External
	subscribers are therefore suitable as notification agents and
	for transporting fault management events.

    Fault Management Protocol Events

	This protocol is defined in the Sun Fault Management Event
	Protocol Specification.  Note that while the API described
	in this manpage is Committed, the protocol events themselves
	(in class names and all event payload) are not Committed along
	with this API.  The protocol specification document describes
	the commitment level of individual event classes and their
	payload content.  In broad terms, the list.* events are
	Committed in most of their content and semantics while events of
	other classes are generally Uncommitted with a few exceptions.

	All protocol events include an identifying class string,
	with the hierarchies defined in the protocol document and
	individual events registered in the Events Registry.  The
	libfmevent mechanism will permit subscription to events with
	Category 1 class of "list" and "swevent", i.e. to classes
	matching patterns "list.*" and "swevent.*".

	All protocol events consist of a number of (name, datatype, value)
	tuples ("nvpairs").  Depending on the event class various nvpairs
	are required and have well-defined meanings.  In Solaris fmd
	protocol events are represented as name-value lists using the
	libnvpair(3LIB) interfaces.

   API Overview

	The API is simple to use in the common case (see EXAMPLES), but
	provides substantial control to cater for more-complex scenarios.

	We obtain an opaque subscription handle using fmev_shdl_init,
	quoting the ABI version and optionally nominating alloc, zalloc
	and free functions (the defaults use the umem family).  More than
	one handle may be opened if desired.  Each handle opened establishes
	a communication channel with fmd, the implementation of which
	is opaque to the libfmevent mechanism.

	On a handle we may establish one or more subscriptions using
	fmev_shdl_subscribe.  Events of interest are specified using a
	simple wildcarded pattern which is matched against the event class
	of incoming events.  For each match that is made a callback is
	performed to a function we associate with the subscription, passing a
	nominated cookie to that function.  Subscriptions may be dropped
	using fmev_shdl_unsubscribe quoting exactly the same class
	or class pattern as was used to establish the subscription.

	Subscription callbacks take place in the context of a dedicated
	set of threads associated with each subscription established
	by a call to fmev_shdl_subscribe.  By default a single thread
	is created when the subscription is established, and additional
	threads are created as incoming event concurrency dictates and
	event callback processing time dictate - if an event matches a
	subscription and all the threads servicing that subscription are
	busy processing earlier events then a new thread is created.
	This behaviour can be modified by using fmev_shdlctl_* before
	subscriptions are made.

	An event callback handler has as arguments
	an opaque event handle, the event class, the event nvlist,
	and the cookie it was registered with in fmev_shdl_subscribe.
	The timestamp for when the event was generated (not when it was
	received) is available as a struct timespec with fmev_timespec,
	or more directly with fmev_time_sec and fmev_time_nsec; an event
	handle and struct tm can also be passed to fmev_localtime to fill
	the struct tm.

	The event handle, class string pointer, and nvlist_t pointer
	passed as arguments to a callback are valid for the duration of
	the callback.  If the application wants to continue to process
	the event beyond the duration of the callback then it can hold the
	event with fmev_hold, and later release it with fmev_rele.
	When the reference count drops to zero the event is freed.

    Error Handling

	In libfmevent.h an enumeration fmev_err_t of error types is
	defined.  To render an error message string from an fmev_err_t
	use fmev_strerror().  An fmev_errno is defined which returns
	the error number for the last failed libfmevent API call made
	by the current thread.  You may not assign to fmev_errno.

	If a function returns type fmev_err_t, then success is indicated
	by FMEV_SUCCESS (or FMEV_OK as an alias); on failure a
	FMEVERR_* value is returned (see libfmevent.h).

	If a function returns a pointer type then failure is indicated
	by a NULL return, and fmev_errno will record the error type.

    Subscription Handles

	A subscription handle is required in order to establish and
	manage subscriptions.  This handle represents the abstract
	communication mechanism between the application and the
	fault management daemon running in the current zone.

	A subscription handle is represented by the opaque fmev_shdl_t
	datatype.  A handle is initialized via fmev_shdl_init and quoted
	to subsequent API members.

	To simplify usage of the API, subscription attributes for all
	subscriptions established on a handle are a property of the
	handle itself - that cannot be varied per-subscription.  In
	such use cases multiple handles will need to be used.

    libfmevent ABI version

	The first argument to fmev_shdl_init indicates the libfmevent
	ABI version that the consumer is opening the handle with - specify
	either LIBFMEVENT_VERSION_LATEST to indicate the most recent version
	available at compile time, or LIBFMEVENT_VERSION_1 (_2 etc
	as the interface evolves) for an explicit choice.

	Interfaces present in an earlier version of the interface will
	continue to be present with the same or compatible semantics in all
	subsequent versions.  When additional interfaces and functionality
	are introduced the ABI version will be incremented.  When an ABI
	version is chosen in fmev_shdl_init, only interfaces introduced in
	or before that version will be available to the application via that
	handle - attempts to use later API members willl fail with
	FMEVERR_VERSION_MISMATCH.

	This manual page describes LIBFMEVENT_VERSION_1.

    Privileges

	A process must have the PRIV_FILE_DAC_READ privilege (see privileges(5))
	to use the libfmevent interface.  This applies to LIBFMEVENT_VERSION_1.
	It is expected that in a future version some more fine-grained
	privilege will be introduced.

    Underlying Event Transport

	The implementation of the event transport by which events are
	published from the fault manager and multiplexed out to libfmevent
	consumers is strictly private.  It is subject to change at any time,
	and you should not encode any dependency on the underlying
	mechanism into your application - keep to the API described here
	and in libfmevent.h.

	The underlying transport does forward events in the order
	they are published within fmd, but since delivery in libfmevent
	is multithreaded by default that order may not be observed
	by subscribers.  See below for controls that allow the serialization
	of event callbacks.

	The underlying transport mechanism is guaranteed to have the
	property that a subscriber may attach to it even before the
	fault manager is running.  If the fault manager starts first
	then any events published before the first consumer subscribes
	will pend in the transport until a consumer appears.

	The underlying transport will also have some maximum depth to
	the queue of events pending delivery.  This may be hit if there
	are no consumers, or if consumers are not processing events
	quickly enough.  In practice the rate of events is small.  When
	this maximum depth is reach additional events will be dropped.

	At this stage the underlying transport has no concept of priority
	delivery - all events are treated equally.

    Subscription Handle Initialization: fmev_shdl_init()

	Obtain a new subscription handle with fmev_shdl_init.  The first
	argument is the libfmevent ABI version to be used (see above).
	The remaining three arguments should be all NULL to leave the
	library to use its default allocator functions (the libumem family),
	or all non-NULL to appoint wrappers to custom allocation functions
	if required.

	FMEVERR_VERSION_MISMATCH:
		The library does not support the version requested.

	FMEVERR_ALLOC:
		An error occured in trying to allocate data structures.

	FMEVERR_API:
		The alloc/zalloc/free arguments must either be all NULL
		or all non-NULL.

	FMEVERR_NOPRIV:
		Insufficient privilege to perform operation.  In version 1
		root privilege is required.

	FMEVERR_INTERNAL:
		Internal library error.

    Subscription Handle Finalization: fmev_shdl_fini()

	Close a subscription handle with fmev_shdl_fini.  This call
	must not be performed from within the context of an event
	callback handler - that will fail with FMEVERR_API.

	The fmev_shdl_fini call will remove all active subscriptions
	on the handle, and free resources used in managing the handle.

	FMEVERR_API:
		May not be called from event delivery context for a
		subscription on same handle.

    Subscribing To Events: fmev_shdl_subscribe()

	To establish a new subscription on a handle, use fmev_shdl_subscribe.
	Besides the handle argument you provide the class or class pattern
	to subscribe to (the latter permitting simple wildcarding using '*'),
	a callback function pointer for a function to be called for all
	matching events, and a cookie to pass to that callback function.

	The class pattern must match events per the fault management
	protocol specification, such as "list.suspect" or "list.*".
	Patterns that do not map onto existing events will not be rejected -
	they just won't result in any callbacks.

	A callback function has type fmev_cbfunc_t.  The first argument is an
	opaque event handle for use in event access functions described below.
	The second argument is the event class string, and the third
	argument is the event nvlist; these could be retrieved using
	fmev_class() and fmev_attr_list() on the event handle, but they're
	supplied as arguments for convenience.  The final argument is the cookie
	requested when the subscription was established in fmev_shdl_subscribe.

	Note that each call to fmev_shdl_subscribe opens a new door into
	the process that the kernel uses for event delivery.  Each
	subscription therefore uses one file decriptor in the process.

	See below for more detail on event callback context.

	FMEVERR_API:
		Class pattern is NULL or callback function is NULL

	FMEVERR_BADCLASS:
		Class pattern is the empty string, or exceeds the maximum
		length of FMEV_MAX_CLASS

	FMEVERR_ALLOC:
		An attempt to fmev_shdl_zalloc additional memory failed

	FMEVERR_DUPLICATE:
		Duplicate subscription request - only one subscription
		for a given class pattern may exist on a handle

	FMEVERR_MAX_SUBSCRIBERS:
		A system-imposed limit on the maximum number of subscribers
		to the underlying transport mechanism has been reached.

	FMEVERR_INTERNAL:
		An unknown error occured in trying to establish the
		subscription.

    Unsubscribing: fmev_shdl_unsubscribe()

	An unsubscribe request must exactly match a previous subscription
	request, or it will fail with FMEVERR_NOMATCH.  The request
	stops further callbacks for this subscription, waits for any
	existing active callbacks to complete, and drops the subscription.

	Do not call fmev_shdl_unsubscribe from event callback context - this
	will fail with FMEVERR_API.

	FMEVERR_API:
		A NULL pattern was specified, or the call was attempted from
		callback context.

	FMEVERR_NOMATCH:
		The pattern provided does not match any open subscription.
		The pattern must be an exact match.

	FMEVERR_BADCLASS:
		The class pattern is the empty string, or exceeds FMEV_MAX_CLASS

    Event Callback Context

	Events are delivered in one or more threads dedicated to each
	subscription.  If no thread is available to service an
	event delivery immediately then the event delivery pends
	until an existing delivery completes (returns).  You can
	control the threads used in delivery using fmev_shdlctl_*.

	Event callback context is defined as the duration of a callback
	event - from the moment we enter the registered callback function
	to the moment it returns.  There are just a few restrictions on
	actions that may be performed from callback context:

	 - you can perform long-running actions, but recall that this
	   thread will not be available to service other event deliveries
	   until you return

	 - you must not cause the current thread to exit

	 - you must not call either fmev_shdl_unsubscribe or
	   fmev_shdl_fini for the subscription handle that this
	   callback has been made on

	 - you can fork, popen etc.

    Event Handles: fmev_t, fmev_hold(), fmev_rele(), fmev_dup()

	A callback receives an fmev_t as a handle on the associated
	event.  The callback may use the access functions described
	below to retrieve various event attributes.

	By default, an event handle fmev_t is valid for the
	duration of the callback context - you cannot access the
	event outside of callback context.

	If you need to continue to work with an event beyond the initial
	callback context in which it is received then you may place
	a "hold" on the event with fmev_hold().  When done with the
	event, release it with fmev_rele().  These calls increment and
	decrement a reference count on the event - when it drops to zero
	the event is freed.  On initial entry to a callback the
	reference count is 1, and this is always decremented when the
	callback returns.

	An alternative to fmev_hold() is fmev_dup() which duplicates the
	event and returns a new event handle, with a reference count of 1.
	When fmev_rele() is applied to the new handle and reduces the
	reference count to 0 the event is freed.  The advantage of
	fmev_dup() is that it allocates new memory to hold the event
	rather than continuing to hold a buffer provided by the underlying
	delivery mechanism - if your operation is going to be long-running
	you may want to use fmev_dup() to avoid starving the underlying
	mechanism of event buffers.

	fmev_hold() and fmev_rele() always succeed.

	fmev_dup may fail and return NULL with fmev_errno of:

		FMEVERR_API - a NULL event handle was passed
		FMEVERR_ALLOC - fmev_shdl_alloc failed
	

   Event Class: fmev_class()

	A delivery callback already receives the event class as an argument,
	so fmev_class() will only be of use outside of callback context (that
	is, for an event that was held or duped in callback context, and
	is now being processed in an asynchronous handler).
	This is a convenience function - it returns the same result
	as accessing the event attributes with fmev_attr_list and using
	nvlist_lookup_string to lookup a string member of name "class".

	The string returned by fmev_class() is valid for as long as the
	event handle itself.

	fmev_class() may fail and return NULL with fmev_errno of:

		FMEVERR_API - a NULL event handle was passed
		FMEVERR_MALFORMED_EVENT - the event appears corrupted

   Event Attribute List: fmev_attr_list()
	
	Recall that all events are defined as a series of (name, type) pairs.
	An instance of an event is therefore a series of tuples
	(name, type, value).  Allowed types are defined in the protocol
	specification.  In Solaris, and in libfmevent, an event is
	represented as an nvlist_t using the libnvpair(3LIB) library.

	The nvlist of event attributes can be accessed using fmev_attr_list.
	The resulting nvlist_t pointer is valid for the same duration as
	the underlying event handle - do not nvlist_free() the nvlist.
	You may then lookup members, iterate over members, and so on using
	the libnvpair(3LIB) interfaces.

	fmev_attr_list() may fail and return NULL with fmev_errno of:

		FMEVERR_API - a NULL event handle was passed
		FMEVERR_MALFORMED_EVENT - the event appears corrupted

    Event Timestamp: fmev_timespec(), fmev_time_sec(), fmev_time_nsec(),
		     fmev_localtime()

	These all refer to the time at which the event was originally
	produced, not the time at which it was forwarded to libfmevent
	or delivered to the callback.

	Use fmev_timespec() to fill a struct timespec with the event
	time in seconds since the Epoch (tv_sec, signed integer) and
	nanoseconds past that second (tv_nsec, a signed long).  This
	call can fail and return FMEVERR_OVERFLOW if the seconds
	value will not fit in a signed 32-bit integer (as used in
	struct timespec tv_sec).

	You can use fmev_time_sec() and fmev_time_nsec() to retrieve
	the same second and nanosecond values as uint64_t quantities.

	Finally, fmev_localtime() takes an event handle and a struct tm
	pointer and will fill that structure according to the timestamp.
	The result is suitable for use with strftime(3C).  This call
	will return NULL and fmev_errno of FMEVERR_OVERFLOW under the
	same conditions as above.

	FMEVERR_OVERFLOW
		fmev_timespec cannot fit the seconds value into the
		signed long integer tv_sec member of a struct timespec

    Memory Allocation: fmev_shdl_alloc(), fmev_shdl_zalloc(), fmev_shdl_free()

	These function simply allocate and free memory using the choices
	made for the given handle when it was initialized - the libumem
	family if all were specified NULL.

    Subscription Handle Control - fmev_shdlctl_*()

	These interfaces offer control over various properties of the
	subscription handle, allowing fine-tuning for particular
	applications.  In the common case the default handle properties
	will suffice.

	These properties apply to the handle and uniformly to all
	subscriptions made on that handle.  The properties
	may only be changed when there are no subscriptions in place on
	the handle, otherwise FMEVERR_BUSY is returned.

	Event delivery is performed through invocations of a private
	door - a new door is opened for each fmev_shdl_subscribe.
	These invocations occur in the context of a private pool of threads
	associated with the door for a subscription.  Many of the
	fmev_shdlctl_* interfaces are concerned with controlling various
	aspects of these delivery threads.

	If you have applied fmev_shdlctl_thrcreate() then "custom thread
	creation semantics" apply on the handle; otherwise "default thread
	creation semantics" are in force.  Some fmev_shdlctl_* interfaces
	only apply to default thread creation semantics.

	fmev_shdlctl_thrmin()

	    This allows you to specify the minimum number of threads
	    that will be created to service each subscription.  During
	    fmev_shdl_subscribe a door is created to allow event delivery
	    callbacks, and the specified number of threads are created to
	    service the door.  The requested value must be at least 1 (the
	    default) and must not exceed any maximum imposed with
	    fmev_shdlctl_thrmax().

	    This control applies to both custom and default thread creation
	    semantics.

		FMEVERR_BUSY
			Subscriptions are in place on this handle

		FMEVERR_INVALIDARG
			Invalid minimum value

	fmev_shdlctl_thrmax()

	    This control applies only to default thread creation semantics.
	    It specifies the maximum number of threads that may be created
	    to service event deliveries for each subscription.  As described
	    above, a number of threads are created to service the subscription
	    when the subscription is established.  When a new event is
	    received for delivery and all threads for the subscription are
	    busy the library will create an additional thread for the new
	    event - up to the maximum value imposed by this interface.

	    The value may be zero (the default) to indicate "no maximum - 
	    create as many threads are incoming concurrency levels
	    and event processing time dictate".  If a non-zero value is
	    requested then it must not be less than the current value
	    set via fmev_shdlctl_thrmin().

		FMEVERR_BUSY
			Subscriptions are in place on this handle

		FMEVERR_INVALIDARG
			Invalid maximum value


	fmev_shdlctl_serialize()

	    This requests that all deliveries on a handle, regardless of
	    which subscription request they are for, be serialized - no
	    concurrent deliveries on this handle.

	    This call has a side-effect of setting both the minimum and
	    maximum number of threads per subscription to one.  Setting
	    those values via fmev_shdlctl_thrmin() and fmev_shdlctl_thrmax()
	    is not equivalent to fmev_shdlctl_serialize() unless exactly
	    one subscription request is in place on the handle.

	    This control applies to both custom and default thread creation
	    semantics.

		FMEVERR_BUSY
			Subscriptions are in place on this handle

	fmev_shdlctl_thrattr()

	    This control applies only to default thread creation semantics.
	    Threads that are created to service subscriptions will be
	    created using pthread_create(3C) using the pthread_attr_t
	    provided via this interface.  The attribute structure is not
	    copied and so must persist for as long as it is in force on
	    the handle.

	    The default thread attributes are also the minimum requirement:
	    threads must be created PTHREAD_CREATE_DETACHED and
	    PTHREAD_SCOPE_SYSTEM.  A NULL pointer for the pthread_attr_t
	    will reinstate these default attributes.

		FMEVERR_BUSY
			Subscriptions are in place on this handle
	    
	fmev_shdlctl_sigmask()
	    
	    This control applies only to default thread creation semantics.
	    Threads that are created to service subscriptions will be
	    be created with the requested signal set masked - a
	    pthread_sigmask request to SIG_SETMASK to this mask prior
	    to pthread_create.  The default is to mask all signals
	    except SIGABRT.

		FMEVERR_BUSY
			Subscriptions are in place on this handle

	fmev_shdlctl_thrsetup()

	    See door_xcreate(3C) for a detailed description of thread
	    setup functions for door server threads.  This function runs
	    in the context of the newly-created thread before it
	    binds to the door created to service the subscription.  It
	    is therefore a suitable place to perform an thread-specific
	    operations the applicaton may require.

	    This control applies to both custom and default thread creation
	    semantics.

		FMEVERR_BUSY
			Subscriptions are in place on this handle

	fmev_shdlctl_thrcreate()

	    See door_xcreate(3C) for a detailed description of thread
	    creation functions for door server threads.  Using this
	    interfaces forfeits the default thread creation semantics
	    described above.  The function appointed is responsible
	    for all of the tasks required of a door_xcreate_server_func_t
	    in door_xcreate(3C).

		FMEVERR_BUSY
			Subscriptions are in place on this handle

EXAMPLE

	The following example subscribes to list.suspect events and
	prints out a simple message for each one that is received.
	It foregoes most error checking for the sake of clarity.

	#include <fm/libfmevent.h>
	#include <libnvpair.h>

	/*
	 * Callback to receive list.suspect events
	 */
	void
	mycb(fmev_t ev, const char *class, nvlist_t *attr, void *cookie)
	{
		struct tm tm;
		char buf[64];
		char *evcode;

		if (strcmp(class, "list.suspect") != 0)
			return;	/* only happens if this code has a bug! */

		(void) strftime(buf, sizeof (buf), NULL,
		    fmev_localtime(ev, &tm));

		(void) nvlist_lookup_string(attr, "code", &evcode);

		(void) fprintf(stderr, "Event class %s published at %s, "
		    "event code %s\n", class, buf, evcode);
	}

	int
	main(int argc, char *argv[])
	{
		fmev_shdl_t hdl;
		sigset_t set;

		hdl = fmev_shdl_init(LIBFMEVENT_VERSION_LATEST,
		    NULL, NULL, NULL);

		(void) fmev_shdl_subscribe(hdl, "list.suspect", mycb, NULL);

		/* Wait here until signalled with SIGTERM to finish */
		(void) sigemptyset(&set);
		(void) sigaddset(&set, SIGTERM);
		(void) sigwait(&set);

		/* fmev_shdl_fini would do this for us if we skipped it */
		(void) fmev_shdl_unsubscribe(hdl, "list.suspect");

		(void) fmev_shdl_fini(hdl);

		return (0);
	}

SEE ALSO
	libnvpair(3LIB), door_xcreate(3C)

ATTRIBUTES

	See attributes(5) for descriptions of the following attributes:

     ____________________________________________________________
    |	    ATTRIBUTE TYPE	  |	  ATTRIBUTE VALUE	|
    |_____________________________|_____________________________|
    | Architecture		  | all				|
    |_____________________________|_____________________________|
    | Availability		  | SUNWfmd			|
    |_____________________________|_____________________________|
    | Interface	Stability	  | Committed
    |_____________________________|_____________________________|
    | MT-Level			  | Safe			|
    |_____________________________|_____________________________|

