/*
* 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
* 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
*/
/*
*/
/*
* Receive (on GPEC channels) raw events published by a few select producers
* using the private libfmevent publication interfaces, and massage those
* raw events into full protocol events. Each raw event selects a "ruleset"
* by which to perform the transformation into a protocol event.
*
* Only publication from userland running privileged is supported; two
* channels are used - one for high-value and one for low-value events.
* There is some planning in the implementation below for kernel hi and low
* value channels, and for non-privileged userland low and hi value channels.
*/
#include <fm/libfmevent.h>
#include <libsysevent.h>
#include <pthread.h>
#include <libnvpair.h>
#include <strings.h>
#include <zone.h>
#include "fmevt.h"
static struct fmevt_inbound_stats {
} inbound_stats = {
{ "raw_callbacks", FMD_TYPE_UINT64,
"total raw event callbacks from producers" },
{ "raw_noattrlist", FMD_TYPE_UINT64,
"missing attribute list" },
{ "raw_nodetector", FMD_TYPE_UINT64,
"unable to add detector" },
{ "pp_bad_ruleset", FMD_TYPE_UINT64,
"post-process bad ruleset" },
{ "pp_explicitdrop", FMD_TYPE_UINT64,
"ruleset drops event with NULL func" },
{ "pp_fanoutmax", FMD_TYPE_UINT64,
"post-processing produced too many events" },
{ "pp_intldrop", FMD_TYPE_UINT64,
"post-processing requested event drop" },
{ "pp_badclass", FMD_TYPE_UINT64,
"post-processing produced invalid event class" },
{ "pp_nvlallocfail", FMD_TYPE_UINT64,
"fmd_nvl_alloc failed" },
{ "pp_nvlbuildfail", FMD_TYPE_UINT64,
"nvlist_add_foo failed in building event" },
{ "pp_badreturn", FMD_TYPE_UINT64,
"inconsistent number of events returned" },
{ "xprt_posted", FMD_TYPE_UINT64,
"protocol events posted with fmd_xprt_post" },
};
static int isglobalzone;
static struct fmevt_chaninfo {
} chaninfo[] = {
{ "user_priv_highval_channel", NULL, { 0 },
{ "user_priv_lowval_channel", NULL, { 0 },
};
static int fmevt_exiting;
/*
* Rulesets we recognize and who handles them. Additions and changes
* must follow the Portfolio Review process. At ths time only
* the FMEV_RULESET_ON_SUNOS and FMEVT_RULESET_SMF rulesets are
* formally recognized by that process - the others here are experimental.
*/
static struct fmevt_rs {
char *rs_pat;
char *rs_namespace;
char *rs_subsys;
} rulelist[] = {
{ FMEV_RULESET_SMF, fmevt_pp_smf },
};
/*
* Take a ruleset specification string and separate it into namespace
* and subsystem components.
*/
static int
{
char *ns, *s;
return (0);
s = ruleset;
return (0);
} else {
return (0);
s++;
}
if (nsp)
if (subsysp)
*subsysp = s; /* always within original ruleset string */
return (1);
}
static int
{
int i;
return (0);
}
return (1);
}
/*
* Construct a "sw" scheme detector FMRI.
*
* We make no use of priv or pri.
*/
/*ARGSUSED3*/
static nvlist_t *
{
int err = 0;
char *str;
return (NULL);
err++;
goto done;
}
/*
* Build up 'object' nvlist.
*/
/*
* Build up 'site' nvlist. We should have source file and line
* number and, if the producer was compiled with C99, function name.
*/
}
}
}
/*
* Build up 'context' nvlist. We do not include contract id at
* this time.
*/
if (execname) {
execname);
}
}
if (!isglobalzone)
/* Put it all together */
done:
if (err == 0) {
return (dtcr);
} else {
return (NULL);
}
}
static int
{
static const char *approved[] = {
FM_IREPORT_CLASS ".",
FM_EREPORT_CLASS "."
};
int i;
return (1);
}
return (0);
}
static void
struct fmevt_ppargs *eap)
{
int i, found = 0;
return;
}
/*
* Lookup a matching rule in our table.
*/
continue;
continue;
found = 1;
break;
}
/*
* If a ruleset matches but specifies a NULL function then
* it's electing to drop the event. If no rule was matched
* then default to unregistered processing.
*/
if (found) {
return;
} else {
}
}
/*
* Clear the arrays in which class strings and attribute
* nvlists can be returned. Pass a pointer to our stack buffer
* that the callee can use for the first event class (for others
* it must fmd_hdl_alloc and we'll free below). We will free
* and nvlists that are returned.
*/
/*
* Generate an event UUID which will be used for the first
* event generated by post-processing; if post-processing
* fans out into more than one event the additional events
* can reference this uuid (but we don't generate their
* UUIDs until later).
*/
/*
* Call selected post-processing function. See block comment
* in fmevt.h for a description of this process.
*/
(const struct fmevt_ppargs *)eap);
if (expected > FMEVT_FANOUT_MAX) {
return; /* without freeing class and nvl - could leak */
} else if (expected == 0) {
return;
}
/*
* Post as many events as the callback completed.
*/
for (i = 0; i < FMEVT_FANOUT_MAX; i++) {
char *uuidstrp;
int err = 0;
continue;
continue;
}
if (processed++ == 0) {
} else {
}
continue;
}
attr[i]);
/*
* If we post the event into fmd_xport_post then the
* transport code is responsible for freeing the nvl we
* posted.
*/
if (err == 0) {
} else {
}
}
for (i = 0; i < FMEVT_FANOUT_MAX; i++) {
/*
* We provided storage for class[0] but any
* additional events have allocated a string.
*/
/*
* Free all attribute lists passed in if they are not
* just a pointer to the raw attributes
*/
nvlist_free(attr[i]);
}
}
static int
{
"invalid flags\n");
(void) pthread_mutex_lock(&fmevt_lock);
if (fmevt_exiting) {
while (fmevt_xprt_refcnt > 0)
(void) pthread_mutex_unlock(&fmevt_lock);
return (0); /* discard event */
}
(void) pthread_mutex_unlock(&fmevt_lock);
goto done;
}
goto done;
}
done:
(void) pthread_mutex_lock(&fmevt_lock);
if (--fmevt_xprt_refcnt == 0 && fmevt_exiting)
(void) pthread_cond_broadcast(&fmevt_cv);
(void) pthread_mutex_unlock(&fmevt_lock);
if (ruleset)
return (0); /* in all cases consider the event delivered */
}
void
{
char *sidpfx;
int i;
if (!fmevt_rs_init(hdl))
"attributes: %s");
int err;
EVCH_CREAT | EVCH_HOLD_PEND_INDEF) != 0)
"channel %s", channel);
"%s_%c%c%c", sidpfx,
"channel %s\n", channel);
else if (err != 0)
channel);
}
}
void
{
int i;
if (cip->ci_binding) {
}
}
if (subattr) {
}
if (fmevt_xprt) {
/* drain before destruction */
(void) pthread_mutex_lock(&fmevt_lock);
fmevt_exiting = 1;
while (fmevt_xprt_refcnt > 0)
(void) pthread_mutex_unlock(&fmevt_lock);
}
}