sysevent_conf_mod.c revision aab83bb83be7342f6cfccaed8d5fe0b2f404855d
/*
* 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
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* sysevent_conf_mod - syseventd daemon sysevent.conf module
*
* This module provides a configuration file registration
* mechanism whereby event producers can define an event
* specification to be matched against events, with an
* associated command line to be invoked for each matching event.
* It includes a simple macro capability for flexibility in
* generating arbitrary command line formats from event-associated
* data, and a user specification so that commands can be invoked
* with reduced privileges to eliminate a security risk.
*
* sysevent.conf files contain event specifications and associated
* command path and optional arguments. System events received
* from the kernel by the sysevent daemon, syseventd, are
* compared against the event specifications in the sysevent.conf
* files. The command as specified by pathname and arguments
* is invoked for each matching event.
*
* All sysevent.conf files reside in /etc/sysevent/config.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <limits.h>
#include <thread.h>
#include <synch.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <pwd.h>
#include <syslog.h>
#include <sys/sysevent.h>
#include <libsysevent.h>
#include <libnvpair.h>
#include <dirent.h>
#include <locale.h>
#include <signal.h>
#include <wait.h>
#include "syseventd.h"
#include "syseventconfd_door.h"
#include "sysevent_conf_mod.h"
#include "message_conf_mod.h"
static char *whoami = "sysevent_conf_mod";
/*
* Event sequencing, time stamp and retry count
*/
static int ev_nretries; /* retry count per event */
static int first_event; /* first event since init */
/*
* State of the sysevent conf table, derived from
*/
/*
* The cmd queue is a queue of commands ready to be sent
* to syseventconfd. Each command consists of the path
* EAGAIN as a result. It is grossly inefficient to bounce
* these events back to syseventd, so we queue them here for delivery.
*/
static int cmdq_cnt;
static thread_t cmdq_thr_id;
static cond_t cmdq_thr_cv;
static int want_fini;
/*
* State of the door channel to syseventconfd
*/
static int confd_state = CONFD_STATE_NOT_RUNNING;
/*
* Number of times to retry event after restarting syeventconfd
*/
static int confd_retries;
/*
* Number of times to retry a failed transport
*/
static int transport_retries;
/*
* Normal sleep time when syseventconfd returns EAGAIN
* is one second but to avoid thrashing, sleep for
* something larger when syseventconfd not responding.
* This should never happen of course but it seems better
* to attempt to handle possible errors gracefully.
*/
static int confd_err_msg_emitted;
static int sysevent_conf_dummy_event(sysevent_t *, int);
/*
* External references
*/
extern int debug_level;
extern char *root_dir;
extern void syseventd_err_print(char *format, ...);
static struct slm_mod_ops sysevent_conf_mod_ops = {
SE_MAJOR_VERSION, /* syseventd module major version */
SE_MINOR_VERSION, /* syseventd module minor version */
SE_MAX_RETRY_LIMIT, /* max retry if EAGAIN */
&sysevent_conf_event /* event handler */
};
static struct slm_mod_ops sysevent_conf_dummy_mod_ops = {
SE_MAJOR_VERSION, /* syseventd module major version */
SE_MINOR_VERSION, /* syseventd module minor version */
0, /* no retries, always succeeds */
&sysevent_conf_dummy_event /* dummy event handler */
};
/*
* skip_spaces() - skip to next non-space character
*/
static char *
skip_spaces(char **cpp)
{
cp++;
if (*cp == 0) {
*cpp = 0;
return (NULL);
}
return (cp);
}
/*
* Get next white-space separated field.
* next_field() will not check any characters on next line.
* Each entry is composed of a single line.
*/
static char *
next_field(char **cpp)
{
char *start;
cp++;
if (*cp == 0) {
*cpp = 0;
return (NULL);
}
cp++;
if (*cp != 0)
*cp++ = 0;
return (start);
}
/*
* The following functions are simple wrappers/equivalents
* for malloc, realloc, free, strdup and a special free
* for strdup.
*
* These functions ensure that any failed mallocs are
* reported via syslog() so if a command is not evoked
* in response to an event, the reason should be logged.
* These functions also provide a convenient place for
* hooks for checking for memory leaks.
*/
static void *
{
void *p;
p = malloc(n);
if (p == NULL) {
}
return (p);
}
/*ARGSUSED*/
static void *
{
p = realloc(p, n);
if (p == NULL) {
}
return (p);
}
/*ARGSUSED*/
static void
{
free(p);
}
static char *
{
char *new;
return (NULL);
}
return (new);
}
static void
sc_strfree(char *s)
{
if (s)
free(s);
}
/*
* The following functions provide some simple dynamic string
* capability. This module has no hard-coded maximum string
* lengths and should be able to parse and generate arbitrarily
* long strings, macro expansion and command lines.
*
* Each string must be explicitly allocated and freed.
*/
/*
* Allocate a dynamic string, with a hint to indicate how
* much memory to dynamically add to the string as it grows
* beyond its existing bounds, so as to avoid excessive
* reallocs as a string grows.
*/
static str_t *
{
return (NULL);
return (str);
}
/*
* Free a dynamically-allocated string
*/
static void
{
}
}
/*
* Reset a dynamically-allocated string, allows reuse
* rather than freeing the old and allocating a new one.
*/
static void
{
}
/*
* Copy a (simple) string onto a dynamically-allocated string
*/
static int
{
char *new_str;
return (1);
}
}
return (0);
}
/*
* Concatenate a (simple) string onto a dynamically-allocated string
*/
static int
{
char *new_str;
return (1);
}
}
return (0);
}
/*
* Concatenate a character onto a dynamically-allocated string
*/
static int
{
char *new_str;
return (1);
}
}
return (0);
}
/*
* fgets() equivalent using a dynamically-allocated string
*/
static char *
{
int c;
return (NULL);
if (c == '\n')
break;
}
return (NULL);
}
/*
* Truncate a dynamically-allocated string at index position 'pos'
*/
static void
{
}
}
/*
* Parse a sysevent.conf file, adding each entry spec to the event table.
*
* The format of an entry in a sysevent.conf file is:
*
* class subclass vendor publisher user reserved1 reserved path arguments
*
* Fields are separated by either SPACE or TAB characters. A
* '#' (number sign) at the beginning of a line indicates a
* comment. Comment lines and blank lines are ignored.
*
* class
* The class of the event.
*
* subclass
* The subclass of the event.
*
* vendor
* The name of the vendor defining the event, usually the
* stock symbol. Events generated by system components
* provided by Sun Microsystems, Inc. always define vendor
* as 'SUNW'.
*
* publisher
* The name of the application, driver or system module
* producing the event.
*
* user
* The name of the user under which the command should be
* run. This allows commands to run with access privileges
* other than those for root. The user field should be '-'
* for commands to be run as root.
*
* reserved1
* Must be '-'.
*
* reserved2
* Must be '-'.
*
* path
* Pathname of the command to be invoked for matching events.
*
* arguments
* Optional argument with possible macro substitution to permit
* arbitrary command line construction with event-specific data.
*/
static void
parse_conf_file(char *conf_file)
{
char *lp;
int lineno = 0;
char *user;
char pwdbuf[1024];
int do_setuid;
int i, err;
return;
}
return;
lineno++;
continue;
goto mal_formed;
goto mal_formed;
goto mal_formed;
goto mal_formed;
goto mal_formed;
goto mal_formed;
goto mal_formed;
goto mal_formed;
/*
* validate user
*/
do_setuid = 0;
continue;
}
do_setuid = 1;
}
/*
* validate reserved fields
*/
continue;
}
continue;
}
/*
* ensure path is executable by user
*/
err = 0;
if (do_setuid) {
err = -1;
}
err = -1;
}
}
}
if (do_setuid) {
err = -1;
}
err = -1;
}
}
continue;
/*
* all sanity tests successful - perform allocations
* to add entry to table
*/
break;
if (do_setuid) {
} else {
}
break;
}
/*
* link new entry into the table
*/
if (syseventtab == NULL) {
syseventtab = sep;
} else {
}
if (debug_level >= DBG_DETAILED) {
" user=%s uid=%d gid=%d\n",
}
}
}
continue;
}
}
/*
* Build the events specification table, a summation of all
* event specification found in the installed sysevent.conf
* configuration files.
*
* All sysevent.conf files reside in the /etc/sysevent/config
* A sysevent.conf file should be named as follows:
*
* <vendor>,[<publisher>,][<class>,]sysevent.conf
*
* system are provided in /etc/sysevent/config/SUNW,sysevent.conf.
* Sun-supplied packages may install additional sysevent.conf
* events required for those products. Products provided
* by third-party hardware or software companies may
* distinguish their sysevent.conf files by vendor, and
*
* as the first character of the name and files with a suffix
* of other than "sysevent.conf" are ignored.
*/
static void
{
char *str;
return;
}
continue;
/*
* file must have extension "sysevent.conf"
*/
str++;
} else {
}
continue;
}
/*
* Add to file table and parse this conf file
*/
goto err;
goto err;
}
} else {
;
}
}
err:
goto err;
}
}
static int
enter_lock(char *lock_file)
{
int lock_fd;
if (lock_fd < 0) {
return (-1);
}
goto retry;
return (-1);
}
return (lock_fd);
}
static void
{
}
}
}
/*
* Free the events specification table, constructed by
* parsing all the sysevent.conf files found.
*
* The free of this table is in response to a HUP
* given to the syseventd daemon, permitting the
* table to be rebuilt after adding a new sysevent.conf
* file or changing an existing one without shutting
* down the daemon.
*/
static void
{
sep = syseventtab;
while (sep) {
}
syseventtab = NULL;
while (cfp) {
}
}
static char ident_chars[] = "_";
/*
* Return a dynamically-allocated string containing the
* the next identifier in the string being parsed, pointed
* at by 'id'. 'end' returns a pointer to the character
* after the identifier.
*
* Identifiers are all alphanumeric ascii characters and
* those contained in ident_chars.
*
* The returned string must be explicitly freed via
* freestr().
*/
static str_t *
{
return (NULL);
while (*id != 0) {
return (NULL);
}
} else {
return (token);
}
}
return (token);
}
/*
* Identical to snip_identifier(), but the identifier
* is delimited by the characters { and }.
*/
static str_t *
{
return (NULL);
while (*id != 0) {
if (*id == '}') {
return (token);
}
return (NULL);
}
}
if (*id == 0) {
return (NULL);
}
return (token);
}
/*
* Return a string with the name of the attribute type
*/
static char *nv_attr_type_strings[] = {
"unknown",
"boolean",
"byte",
"int16",
"uint16",
"int32",
"uint32",
"int64",
"uint64",
"string",
"byte-array",
"int16-array",
"uint16-array",
"int32-array",
"uint32-array",
"int64-array",
"uint64-array",
"string-array",
"hrtime"
};
static char *
{
if (se_attr_type >= 0 &&
se_attr_type < sizeof (nv_attr_type_strings) / sizeof (char *)) {
return (nv_attr_type_strings[se_attr_type]);
}
return (nv_attr_type_strings[DATA_TYPE_UNKNOWN]);
}
/*
* Find and return the data matching the macro name 'token'
*
* Predefined macros are simply substituted with the
* data from the event header:
*
* $vendor - the vendor string defining the event.
*
* $publisher - the publisher string defining the event.
*
* $class - the class string defining the event.
*
* $subclass - the subclass string defining the event.
*
* $sequence - the sequence number of the event.
*
* $timestamp - the timestamp of the event.
*
* Attributes with signed data types (DATA_TYPE_INT16,
* DATA_TYPE_INT32 and DATA_TYPE_INT64) are expanded
* as decimal digits.
*
* Attributes with unsigned data types (DATA_TYPE_BYTE,
* DATA_TYPE_UINT16, DATA_TYPE_UINT32, DATA_TYPE_UINT64 and
* DATA_TYPE_HTTIME) are expanded as hexadecimal digits
* with a "0x" prefix.
*
* Attributes with string data type (DATA_TYPE_STRING)
* are expanded with the string data. The data is
* not quoted. If if it desired that the quoted strings
* be generated on the command line, put quotes around
* the macro call in the arguments.
*
* Array types are expanded with each element expanded
* as defined for that scalar type, with a space separating
* each element substitution.
*/
static str_t *
{
int nmatches;
char num[64];
int i;
union {
char *x_string;
char **x_string_array;
} x;
return (NULL);
}
return (NULL);
}
return (replacement);
}
return (NULL);
}
return (replacement);
}
return (NULL);
}
return (replacement);
}
return (NULL);
}
return (replacement);
}
} else {
}
return (NULL);
}
return (replacement);
}
nmatches = 0;
if (nvlist) {
if (debug_level >= DBG_DETAILED) {
}
nmatches++;
}
}
}
if (nmatches == 0) {
return (NULL);
} else if (nmatches > 1) {
return (NULL);
}
switch (nvpair_type(nvp)) {
case DATA_TYPE_BYTE:
return (NULL);
}
break;
case DATA_TYPE_INT16:
return (NULL);
}
break;
case DATA_TYPE_UINT16:
return (NULL);
}
break;
case DATA_TYPE_INT32:
return (NULL);
}
break;
case DATA_TYPE_UINT32:
return (NULL);
}
break;
case DATA_TYPE_INT64:
return (NULL);
}
break;
case DATA_TYPE_UINT64:
return (NULL);
}
break;
case DATA_TYPE_STRING:
return (NULL);
}
break;
case DATA_TYPE_BYTE_ARRAY: {
uchar_t *p;
(void) nvpair_value_byte_array(nvp,
&x.x_byte_array, &nelems);
p = x.x_byte_array;
for (i = 0; i < nelems; i++) {
"0x%x ", *p++ & 0xff);
return (NULL);
}
}
}
break;
case DATA_TYPE_INT16_ARRAY: {
int16_t *p;
(void) nvpair_value_int16_array(nvp,
&x.x_int16_array, &nelems);
p = x.x_int16_array;
for (i = 0; i < nelems; i++) {
return (NULL);
}
}
}
break;
case DATA_TYPE_UINT16_ARRAY: {
uint16_t *p;
(void) nvpair_value_uint16_array(nvp,
&x.x_uint16_array, &nelems);
p = x.x_uint16_array;
for (i = 0; i < nelems; i++) {
"0x%x ", *p++);
return (NULL);
}
}
}
break;
case DATA_TYPE_INT32_ARRAY: {
int32_t *p;
(void) nvpair_value_int32_array(nvp,
&x.x_int32_array, &nelems);
p = x.x_int32_array;
for (i = 0; i < nelems; i++) {
return (NULL);
}
}
}
break;
case DATA_TYPE_UINT32_ARRAY: {
uint32_t *p;
(void) nvpair_value_uint32_array(nvp,
&x.x_uint32_array, &nelems);
p = x.x_uint32_array;
for (i = 0; i < nelems; i++) {
"0x%x ", *p++);
return (NULL);
}
}
}
break;
case DATA_TYPE_INT64_ARRAY: {
int64_t *p;
(void) nvpair_value_int64_array(nvp,
&x.x_int64_array, &nelems);
p = x.x_int64_array;
for (i = 0; i < nelems; i++) {
"%lld ", *p++);
return (NULL);
}
}
}
break;
case DATA_TYPE_UINT64_ARRAY: {
uint64_t *p;
(void) nvpair_value_uint64_array(nvp,
&x.x_uint64_array, &nelems);
p = x.x_uint64_array;
for (i = 0; i < nelems; i++) {
"0x%llx ", *p++);
return (NULL);
}
}
}
break;
case DATA_TYPE_STRING_ARRAY: {
char **p;
(void) nvpair_value_string_array(nvp,
&x.x_string_array, &nelems);
p = x.x_string_array;
for (i = 0; i < nelems; i++) {
if (strcats(replacement, *p++) ||
return (NULL);
}
}
}
break;
case DATA_TYPE_HRTIME:
return (NULL);
}
break;
default:
return (NULL);
}
return (replacement);
}
/*
* Expand macros in the command template provided in an event
* specification with the data from the event or event attributes.
*
* Macros are introduced by the '$' character, with the macro
* name being the following token separated by a SPACE or
* TAB character. If the macro name is embedded in text,
* it may be delineated by '${' and "}'. A backslash before
* the '$' causes macro expansion not to occur.
*
* The following predefined macros are defined for each event:
*
* $vendor - the vendor string defining the event.
*
* $publisher - the publisher string defining the event.
*
* $class - the class string defining the event.
*
* $subclass - the subclass string defining the event.
*
* $sequence - the sequence number of the event.
*
* $timestamp - the timestamp of the event.
*
*
* Macro names other than those predefined are compared against
* the attribute list provided with the event. An attribute
* with name matching the macro name causes the value of
* of the attribute to be substituted as ASCII text on the
* generated command line.
*
* Use of a macro for which no attribute with that name
* is defined, or for which multiple attributes with that
* name are provided, cause an error and the command is
* not invoked.
*/
static int
{
char *p;
int state;
char *end;
int count;
int dollar_position;
state = 0;
count = 0;
switch (state) {
case 0: /* initial state */
if (*p == '\\') {
state = 1;
} else if (*p == '$') {
state = 2;
}
break;
case 1: /* skip characters */
state = 0; /* after backslash */
break;
case 2: /* character after $ */
if (*p == '{') {
} else {
}
goto failed;
return (1);
}
return (1);
}
if (replacement == NULL) {
return (1);
}
" '%s' expands to '%s'\n",
return (1);
}
return (1);
}
goto reset;
}
}
if (state != 0) {
return (1);
}
return (0);
}
static void
{
int err;
"/usr/lib/sysevent/syseventconfd");
if (err != 0 && confd_err_msg_emitted == 0) {
if (confd_state == CONFD_STATE_NOT_RUNNING) {
} else {
}
}
}
static int
{
int status, w;
/* Check the requested command */
if (s == NULL) {
return (-1);
}
/* Check the ability to execute devfsadmd from this process */
return (-1);
}
return (-1);
}
/*
* Block SIGCHLD and set up a default handler for the duration of the
* system1 call.
*/
(void) sigemptyset(&mask);
/* Fork off the child process (using fork1(), because it's MT-safe) */
case -1:
/* Error */
return (-1);
case 0:
/* Set-up an initial signal mask for the child */
(void) sigemptyset(&mask);
closefrom(3);
_exit(-1);
break;
default:
/* Parent */
break;
}
do {
return ((w == -1)? w: status);
}
/*
* Free all commands on the cmd queue
*/
static void
{
int nevents = 0;
cmdq_cnt--;
nevents++;
}
/*
* Generate error msgs if events were discarded or
* we are entering the disabled state.
*/
if (nevents > 0) {
}
if (want_fini == 0) {
}
}
/*
* For a matching event specification, build the command to be
* invoked in response to the event. Building the command involves
* expanding macros supplied in the event specification command
* with values from the actual event. These macros can be
* attribute data attached to the event.
*
* since this module is running in the context of the syseventd
* upcall delivering events from the kernel to the daemon.
* Instead, we build a separate event and nvlist with the
* attributes of the command to be invoked, and pass that on
* server on our behalf.
*
* Errors queuing the event are returned to syseventd with
* EAGAIN, allowing syseventd to manage a limited number of
* retries after a short delay.
*/
static int
{
char *argv0;
return (1);
} else {
argv0++;
}
return (1);
}
return (1);
}
return (1);
}
return (1);
}
return (1);
}
}
if (debug_level >= DBG_EXEC) {
}
cmd_nvlist = NULL;
return (1);
}
goto err;
goto err;
sep->se_conf_file)) != 0)
goto err;
goto err;
goto err;
goto err;
goto err;
}
return (1);
}
/*
* Place cmd_event on queue to be transported to syseventconfd
*/
return (1);
}
(void) mutex_lock(&cmdq_lock);
} else {
}
cmdq_cnt++;
/*
* signal queue flush thread
*/
(void) cond_signal(&cmdq_cv);
(void) mutex_unlock(&cmdq_lock);
return (0);
err:
return (1);
}
static int
{
int rval;
if (rval != 0) {
switch (errno) {
case EAGAIN:
case EINTR:
/*
* syseventconfd daemon may be forking, stop
* attempting to empty the queue momentarily.
*/
break;
case ENOENT:
case EBADF:
/*
* allowing for some delay when starting
* up before it begins to reply.
*/
if (confd_state == CONFD_STATE_NOT_RUNNING ||
confd_state == CONFD_STATE_OK) {
confd_retries = 0;
} else if (confd_state == CONFD_STATE_STARTED &&
confd_retries < 16) {
if (++confd_retries == 16) {
if (confd_err_msg_emitted == 0) {
}
}
} else {
}
break;
default:
break;
}
} else if (confd_state != CONFD_STATE_OK) {
if (confd_state == CONFD_STATE_ERR) {
}
confd_retries = 0;
}
return (rval);
}
/*
* Send events on queue to syseventconfd daemon. We queue events
* here since the daemon is unable to handle events during an
* inefficient to bounce these events back to syseventd, so
* we queue them here for delivery.
*
* syseventconfd itself, just the daemon is busy or some
* other transient difficulty. We retry EBADF and other errors
* for some time, then eventually give up - something's broken.
*
* Error handling strategy:
* If we're trying to shut down and the syseventconfd daemon isn't
* responding, abort the queue so we don't cause the fini to hang
* we presume the daemon is active but either busy or some transient
* state is preventing the transport. We make considerable effort
* to retry EBADF since the daemon may take some time to come up when
* restarted so don't want to give up too easily. Once we enter
* the DISABLED state, we stop handling events altogther to
* avoid thrashing the system if the syseventconfd binary is
* corrupted or missing. This state can be cleared by issuing
* a HUP signal to the syseventd daemon. For errors other than
* a certain number of these in a row, we enter the DISABLED
* state.
*/
static void
{
int rval;
(void) mutex_lock(&cmdq_lock);
(void) mutex_unlock(&cmdq_lock);
(void) mutex_lock(&cmdq_lock);
if (rval != 0) {
switch (rval) {
case EAGAIN:
case EINTR:
/*
* Limit retries in the case of fini
*/
if (want_fini) {
if (++transport_retries == 16) {
}
}
(void) mutex_unlock(&cmdq_lock);
return;
case EBADF:
/*
* retry up to 16 times
*/
}
(void) mutex_unlock(&cmdq_lock);
return;
default:
/*
* After 16 sequential errors, give up
*/
if (++transport_retries == 16) {
(void) mutex_unlock(&cmdq_lock);
return;
}
/*
* We don't retry these errors, we
* fall through to remove this event
* from the queue.
*/
break;
}
} else {
transport_retries = 0;
}
/*
* Take completed event off queue
*/
cmdq_cnt--;
}
(void) mutex_unlock(&cmdq_lock);
(void) mutex_lock(&cmdq_lock);
}
(void) mutex_unlock(&cmdq_lock);
}
static void
{
int n;
(void) mutex_lock(&cmdq_lock);
for (;;) {
}
(void) cond_signal(&cmdq_thr_cv);
(void) mutex_unlock(&cmdq_lock);
/*NOTREACHED*/
}
(void) mutex_unlock(&cmdq_lock);
(void) mutex_lock(&cmdq_lock);
if (cmdq_cnt != 0) {
(void) mutex_unlock(&cmdq_lock);
if (want_fini == 0 && confd_err_msg_emitted) {
for (n = 0; n < 60; n++) {
(void) sleep(1);
if (want_fini)
break;
}
} else {
(void) sleep(1);
}
(void) mutex_lock(&cmdq_lock);
}
}
}
/*
* syseventd daemon module event handler
*
* The syseventd daemon calls this handler with each event
* for this module to handle the event as appropriate.
* The task of this module is to compare the event's
* event specifications provided in the installed
* sysevent.conf files. Build and execute the
* defined command for that event specification
* for each match.
*
* Events are matched against the class, subclass, vendor
* and publisher specifications. Any field not to be matched
* against an event should be set to '-'. A specification
* of '- - - -' generates a match against every event.
*/
/*ARGSUSED*/
static int
{
int ret = 0;
char *vendor;
char *publisher;
char *class;
char *subclass;
/*
* If we've been completely unable to communicate with
* syseventconfd, there's not much we can do.
*/
if (confd_state == CONFD_STATE_DISABLED) {
return (0);
}
/*
* sysevent_get_seq(ev) < ev_seq):
* an event we have played before, ignore it
* sysevent_get_seq(ev) == ev_seq):
* ev_nretries > 0, an event being retried
* sysevent_get_seq(ev) > ev_seq):
* a new event
*/
if (debug_level >= DBG_EVENTS) {
"sequence: %lld/%lld, retry %d\n",
"sequence: %lld/%lld\n",
}
}
ev_nretries = 0;
} else if (first_event == 0 &&
"out-of-order sequence: received %lld/0x%llx, "
return (ret);
}
first_event = 0;
/*
* sysevent_get_vendor_name() and sysevent_get_pub_name()
* allocate strings which must be freed.
*/
/* Temporary short on memory */
ev_nretries++;
return (EAGAIN);
}
"%s event %lld: vendor='%s' publisher='%s' class='%s' "
continue;
}
continue;
}
continue;
}
continue;
}
break;
}
if (ret == 0) {
ev_nretries = 0;
} else {
/*
* Ask syseventd to retry any failed event. If we have
* reached the limit on retries, emit a msg that we're
* not going to be able to service it.
*/
if (ev_nretries == SE_MAX_RETRY_LIMIT) {
} else {
"'%s' '%s' '%s' '%s - errno %d, retry %d\n",
}
ev_nretries++;
}
return (ret);
}
/*
* syseventd daemon module initialization
*/
struct slm_mod_ops *
slm_init()
{
int lock_fd;
int err;
/*
* This functionality is not supported in the mini-root
* environment, ie install. If root_dir is set, implying
* install, we quietly fail. Return dummy ops rather
* than NULL to avoid error msgs out of syseventd.
*/
return (&sysevent_conf_dummy_mod_ops);
}
ev_nretries = 0;
first_event = 1;
/*
* Initialize the channel to syseventconfd
*/
if (confd_handle == NULL) {
return (NULL);
}
if (sysevent_bind_publisher(confd_handle) != 0) {
if (sysevent_bind_publisher(confd_handle) != 0) {
return (NULL);
}
}
}
cmdq_cnt = 0;
want_fini = 0;
if (confd_state != CONFD_STATE_OK) {
}
confd_retries = 0;
transport_retries = 0;
/*
* Create thread to flush cmd queue
*/
(void *)NULL, 0, &cmdq_thr_id)) != 0) {
confd_handle = NULL;
(void) mutex_destroy(&cmdq_lock);
(void) cond_destroy(&cmdq_cv);
(void) cond_destroy(&cmdq_thr_cv);
return (NULL);
}
confd_handle = NULL;
(void) mutex_destroy(&cmdq_lock);
(void) cond_destroy(&cmdq_cv);
(void) cond_destroy(&cmdq_thr_cv);
return (NULL);
}
return (&sysevent_conf_mod_ops);
}
/*
* syseventd daemon module tear-down
*/
void
slm_fini()
{
int err;
/*
* Nothing to clean up if we're in the install environment
*/
return;
}
/*
* Wait for the queue to drain
*/
(void) mutex_lock(&cmdq_lock);
want_fini = 1;
(void) cond_signal(&cmdq_cv);
(void) mutex_unlock(&cmdq_lock);
/*
* Shut down the the queue flush thread
*/
}
confd_handle = NULL;
(void) mutex_destroy(&cmdq_lock);
(void) cond_destroy(&cmdq_cv);
(void) cond_destroy(&cmdq_thr_cv);
}
/*ARGSUSED*/
static int
{
return (0);
}