From 820d9e6bb32db5ff73f0722815c4044951d590e4 Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Wed, 20 Apr 2005 22:48:49 +0000 Subject: [PATCH] massive overhaul to ipmievd to support both openipmi event message buffer and manual SEL polling --- ipmitool/src/ipmievd.c | 734 ++++++++++++++++++++++++++++++----------- 1 file changed, 544 insertions(+), 190 deletions(-) diff --git a/ipmitool/src/ipmievd.c b/ipmitool/src/ipmievd.c index 8621dea..5aea545 100644 --- a/ipmitool/src/ipmievd.c +++ b/ipmitool/src/ipmievd.c @@ -44,95 +44,275 @@ #include #include #include -#include #ifdef __FreeBSD__ -#include -#include +# include +# include #endif #include -#ifdef HAVE_OPENIPMI_H -# include -# include -#else -# include "plugins/open/open.h" -#endif +#ifdef IPMI_INTF_OPEN +# ifdef HAVE_OPENIPMI_H +# include +# include +# include +# else /* HAVE_OPENIPMI_H */ +# include "plugins/open/open.h" +# endif /* HAVE_OPENIPMI_H */ +#endif /* IPMI_INTF_OPEN */ #include #include #include #include #include +#include +#include +#include +/* global variables */ extern int errno; int verbose = 0; int csv_output = 0; +uint16_t selwatch_count = 0; /* number of entries in the SEL */ +uint16_t selwatch_lastid = 0; /* current last entry in the SEL */ +int selwatch_timeout = 10; /* default to 10 seconds */ -static void daemonize(void) +/* event interface definition */ +struct ipmi_event_intf { + char name[16]; + char desc[128]; + int (*setup)(struct ipmi_event_intf * eintf); + int (*wait)(struct ipmi_event_intf * eintf); + int (*read)(struct ipmi_event_intf * eintf); + int (*check)(struct ipmi_event_intf * eintf); + void (*log)(struct ipmi_event_intf * eintf, struct sel_event_record * evt); + struct ipmi_intf * intf; +}; + +static void log_event(struct ipmi_event_intf * eintf, struct sel_event_record * evt); + +/* ~~~~~~~~~~~~~~~~~~~~~~ openipmi ~~~~~~~~~~~~~~~~~~~~ */ +#ifdef IPMI_INTF_OPEN +static int openipmi_setup(struct ipmi_event_intf * eintf); +static int openipmi_wait(struct ipmi_event_intf * eintf); +static int openipmi_read(struct ipmi_event_intf * eintf); +static int openipmi_check(struct ipmi_event_intf * eintf); +static struct ipmi_event_intf openipmi_event_intf = { + name: "open", + desc: "OpenIPMI asyncronous notification of events", + setup: openipmi_setup, + wait: openipmi_wait, + read: openipmi_read, + log: log_event, +}; +#endif +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* ~~~~~~~~~~~~~~~~~~~~~~ selwatch ~~~~~~~~~~~~~~~~~~~~ */ +static int selwatch_setup(struct ipmi_event_intf * eintf); +static int selwatch_wait(struct ipmi_event_intf * eintf); +static int selwatch_read(struct ipmi_event_intf * eintf); +static int selwatch_check(struct ipmi_event_intf * eintf); +static struct ipmi_event_intf selwatch_event_intf = { + name: "sel", + desc: "Poll SEL for notification of events", + setup: selwatch_setup, + wait: selwatch_wait, + read: selwatch_read, + check: selwatch_check, + log: log_event, +}; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +struct ipmi_event_intf * ipmi_event_intf_table[] = { +#ifdef IPMI_INTF_OPEN + &openipmi_event_intf, +#endif + &selwatch_event_intf, + NULL +}; + +/*************************************************************************/ + +/* ipmi_event_intf_print - Print list of event interfaces + * + * no meaningful return code + */ +static void +ipmi_event_intf_print(void) { - pid_t pid; - int fd; -#ifdef SIGHUP - sigset_t sighup; -#endif + struct ipmi_event_intf ** intf; + int def = 1; - /* if we are started from init no need to become daemon */ - if (getppid() == 1) - return; + lprintf(LOG_NOTICE, "Event Handlers:"); -#ifdef SIGHUP - sigemptyset(&sighup); - sigaddset(&sighup, SIGHUP); - if (sigprocmask(SIG_UNBLOCK, &sighup, NULL) < 0) - fprintf(stderr, "ERROR: could not unblock SIGHUP signal\n"); - signal(SIGHUP, SIG_IGN); -#endif -#ifdef SIGTTOU - signal(SIGTTOU, SIG_IGN); -#endif -#ifdef SIGTTIN - signal(SIGTTIN, SIG_IGN); -#endif -#ifdef SIGQUIT - signal(SIGQUIT, SIG_IGN); -#endif -#ifdef SIGTSTP - signal(SIGTSTP, SIG_IGN); -#endif - - pid = (pid_t) fork(); - if (pid < 0 || pid > 0) - exit(0); - -#if defined(SIGTSTP) && defined(TIOCNOTTY) - if (setpgid(0, getpid()) == -1) - exit(1); - if ((fd = open(_PATH_TTY, O_RDWR)) >= 0) { - ioctl(fd, TIOCNOTTY, NULL); - close(fd); + for (intf = ipmi_event_intf_table; intf && *intf; intf++) { + lprintf(LOG_NOTICE, "\t%-12s %s %s", + (*intf)->name, (*intf)->desc, + def ? "[default]" : ""); + def = 0; } -#else - if (setpgrp() == -1) - exit(1); - pid = (pid_t) fork(); - if (pid < 0 || pid > 0) - exit(0); -#endif - - chdir("/"); - umask(0); - - for (fd=0; fd<64; fd++) - close(fd); - - open("/dev/null", O_RDWR); - dup(0); - dup(0); + lprintf(LOG_NOTICE, ""); } -static int enable_event_msg_buffer(struct ipmi_intf * intf) +static void +ipmievd_usage(void) +{ + lprintf(LOG_NOTICE, "Options:"); + lprintf(LOG_NOTICE, "\ttimeout=# Time between checks for SEL polling method [default=10]"); + lprintf(LOG_NOTICE, "\tdaemon Become a daemon [default]"); + lprintf(LOG_NOTICE, "\tnodaemon Do NOT become a daemon"); +} + +/* ipmi_intf_load - Load an event interface from the table above + * If no interface name is given return first entry + * + * @name: interface name to try and load + * + * returns pointer to inteface structure if found + * returns NULL on error + */ +static struct ipmi_event_intf * +ipmi_event_intf_load(char * name) +{ + struct ipmi_event_intf ** intf; + struct ipmi_event_intf * i; + + if (name == NULL) { + i = ipmi_event_intf_table[0]; + return i; + } + + for (intf = ipmi_event_intf_table; + ((intf != NULL) && (*intf != NULL)); + intf++) { + i = *intf; + if (strncmp(name, i->name, strlen(name)) == 0) { + return i; + } + } + + return NULL; +} + +static void +log_event(struct ipmi_event_intf * eintf, struct sel_event_record * evt) +{ + char *desc; + const char *type; + struct sdr_record_list * sdr, * list, * entry; + struct entity_id entity; + struct ipmi_rs * readrsp; + struct ipmi_intf * intf = eintf->intf; + float trigger_reading = 0.0; + float threshold_reading = 0.0; + + if (evt == NULL) + return; + + if (evt->record_type == 0xf0) { + lprintf(LOG_ALERT, "Linux kernel panic: %.11s", (char *) evt + 5); + return; + } + else if (evt->record_type >= 0xc0) { + lprintf(LOG_NOTICE, "IPMI Event OEM Record %02x", evt->record_type); + return; + } + + type = ipmi_sel_get_sensor_type_offset(evt->sensor_type, evt->event_data[0]); + ipmi_get_event_desc(evt, &desc); + + sdr = ipmi_sdr_find_sdr_bynumtype(intf, evt->sensor_num, evt->sensor_type); + if (sdr == NULL) { + /* could not find matching SDR record */ + if (desc) { + lprintf(LOG_NOTICE, "%s sensor - %s", + type, desc); + free(desc); + } else { + lprintf(LOG_NOTICE, "%s sensor %02x", + type, evt->sensor_num); + } + return; + } + + switch (sdr->type) { + case SDR_RECORD_TYPE_FULL_SENSOR: + if (evt->event_type == 1) { + /* + * Threshold Event + */ + + /* trigger reading in event data byte 2 */ + if (((evt->event_data[0] >> 6) & 3) == 1) { + trigger_reading = sdr_convert_sensor_reading( + sdr->record.full, evt->event_data[1]); + } + + /* trigger threshold in event data byte 3 */ + if (((evt->event_data[0] >> 4) & 3) == 1) { + threshold_reading = sdr_convert_sensor_reading( + sdr->record.full, evt->event_data[2]); + } + + lprintf(LOG_NOTICE, "%s sensor %s %s (Reading %.*f %s Threshold %.*f %s)", + type, + sdr->record.full->id_string, + desc ? : "", + (trigger_reading==(int)trigger_reading) ? 0 : 2, + trigger_reading, + ((evt->event_data[0] & 0xf) % 2) ? ">" : "<", + (threshold_reading==(int)threshold_reading) ? 0 : 2, + threshold_reading, + ipmi_sdr_get_unit_string(sdr->record.full->unit.modifier, + sdr->record.full->unit.type.base, + sdr->record.full->unit.type.modifier)); + } + else if ((evt->event_type >= 0x2 && evt->event_type <= 0xc) || + (evt->event_type == 0x6f)) { + /* + * Discrete Event + */ + lprintf(LOG_NOTICE, "%s sensor %s %s", + type, sdr->record.full->id_string, desc ? : ""); + if (((evt->event_data[0] >> 6) & 3) == 1) { + /* previous state and/or severity in event data byte 2 */ + } + } + else if (evt->event_type >= 0x70 && evt->event_type <= 0x7f) { + /* + * OEM Event + */ + lprintf(LOG_NOTICE, "%s sensor %s %s", + type, sdr->record.full->id_string, desc ? : ""); + } + break; + + case SDR_RECORD_TYPE_COMPACT_SENSOR: + lprintf(LOG_NOTICE, "%s sensor %s - %s", + type, sdr->record.compact->id_string, desc ? : ""); + break; + + default: + lprintf(LOG_NOTICE, "%s sensor - %s", + type, evt->sensor_num, desc ? : ""); + break; + } + + if (desc) + free(desc); +} +/*************************************************************************/ + + +/*************************************************************************/ +/** OpenIPMI Functions **/ +/*************************************************************************/ +#ifdef IPMI_INTF_OPEN +static int +openipmi_enable_event_msg_buffer(struct ipmi_intf * intf) { struct ipmi_rs * rsp; struct ipmi_rq req; @@ -144,9 +324,13 @@ static int enable_event_msg_buffer(struct ipmi_intf * intf) req.msg.cmd = 0x2f; /* Get BMC Global Enables */ rsp = intf->sendrecv(intf, &req); - if (!rsp || rsp->ccode) { - lprintf(LOG_WARNING, "Get BMC Global Enables command filed [ccode %02x]", - rsp ? rsp->ccode : 0); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get BMC Global Enables command failed"); + return -1; + } + else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get BMC Global Enables command failed: %s", + val2str(rsp->ccode, completion_code_vals)); return -1; } @@ -156,9 +340,13 @@ static int enable_event_msg_buffer(struct ipmi_intf * intf) req.msg.data_len = 1; rsp = intf->sendrecv(intf, &req); - if (!rsp || rsp->ccode) { - lprintf(LOG_WARNING, "Set BMC Global Enables command failed [ccode %02x]", - rsp ? rsp->ccode : 0); + if (rsp == NULL) { + lprintf(LOG_ERR, "Set BMC Global Enables command failed"); + return -1; + } + else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set BMC Global Enables command failed: %s", + val2str(rsp->ccode, completion_code_vals)); return -1; } @@ -167,29 +355,33 @@ static int enable_event_msg_buffer(struct ipmi_intf * intf) return 0; } -static void log_event(struct sel_event_record * evt) +static int +openipmi_setup(struct ipmi_event_intf * eintf) { - char *desc; + int i, r; - if (!evt) - return; - - if (evt->record_type == 0xf0) - lprintf(LOG_ALERT, "Linux kernel panic: %.11s", (char *) evt + 5); - else if (evt->record_type >= 0xc0) - lprintf(LOG_NOTICE, "IPMI Event OEM Record %02x", evt->record_type); - else { - ipmi_get_event_desc(evt, &desc); - if (desc) { - lprintf(LOG_NOTICE, "%s Sensor %02x - %s", - ipmi_sel_get_sensor_type(evt->sensor_type), - evt->sensor_num, desc); - free(desc); - } + /* enable event message buffer */ + lprintf(LOG_DEBUG, "Enabling event message buffer"); + r = openipmi_enable_event_msg_buffer(eintf->intf); + if (r < 0) { + lprintf(LOG_ERR, "Could not enable event message buffer"); + return -1; } + + /* enable OpenIPMI event receiver */ + lprintf(LOG_DEBUG, "Enabling event receiver"); + i = 1; + r = ioctl(eintf->intf->fd, IPMICTL_SET_GETS_EVENTS_CMD, &i); + if (r != 0) { + lperror(LOG_ERR, "Could not enable event receiver"); + return -1; + } + + return 0; } -static void read_event(struct ipmi_intf * intf) +static int +openipmi_read(struct ipmi_event_intf * eintf) { struct ipmi_addr addr; struct ipmi_recv recv; @@ -201,127 +393,44 @@ static void read_event(struct ipmi_intf * intf) recv.msg.data = data; recv.msg.data_len = sizeof(data); - rv = ioctl(intf->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv); + rv = ioctl(eintf->intf->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv); if (rv < 0) { switch (errno) { case EINTR: - return; /* abort */ + return 0; /* abort */ case EMSGSIZE: recv.msg.data_len = sizeof(data); /* truncated */ break; default: lperror(LOG_ERR, "Unable to receive IPMI message"); - return; + return -1; } } if (!recv.msg.data || recv.msg.data_len == 0) { lprintf(LOG_ERR, "No data in event"); - return; + return -1; } if (recv.recv_type != IPMI_ASYNC_EVENT_RECV_TYPE) { lprintf(LOG_ERR, "Type %x is not an event", recv.recv_type); - return; + return -1; } lprintf(LOG_DEBUG, "netfn:%x cmd:%x ccode:%d", recv.msg.netfn, recv.msg.cmd, recv.msg.data[0]); - log_event((struct sel_event_record *)recv.msg.data); + eintf->log(eintf, (struct sel_event_record *)recv.msg.data); } -static int do_exit(struct ipmi_intf * intf, int rv) +static int +openipmi_wait(struct ipmi_event_intf * eintf) { - if (intf) - intf->close(intf); - log_halt(); - exit(rv); -} - -static void usage(void) -{ - fprintf(stderr, "usage: ipmievd [-hvd]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -h This help\n"); - fprintf(stderr, " -v Verbose (can use multiple times)\n"); - fprintf(stderr, " -s Do NOT daemonize\n"); - fprintf(stderr, "\n"); -} - -int main(int argc, char ** argv) -{ - struct ipmi_intf * intf; - int r, a; - int i = 1; - int daemon = 1; struct pollfd pfd; - - /* make sure we have UID 0 */ - if (geteuid() || getuid()) { - fprintf(stderr, "Inadequate privledges\n"); - do_exit(NULL, EXIT_FAILURE); - } - - while ((a = getopt(argc, (char **)argv, "hvs")) != -1) { - switch (a) { - case 'h': - usage(); - do_exit(NULL, EXIT_SUCCESS); - break; - case 'v': - verbose++; - break; - case 's': - daemon = 0; - break; - default: - usage(); - do_exit(NULL, EXIT_FAILURE); - } - } - - if (daemon) - daemonize(); - - log_init("ipmievd", daemon, verbose); - - /* load interface */ - lprintf(LOG_DEBUG, "Loading OpenIPMI interface"); - intf = ipmi_intf_load("open"); - if (!intf) { - lprintf(LOG_ERR, "Unable to load OpenIPMI interface"); - do_exit(NULL, EXIT_FAILURE); - } - - /* open connection to openipmi device */ - lprintf(LOG_DEBUG, "Connecting to OpenIPMI device"); - r = intf->open(intf); - if (r < 0) { - lprintf(LOG_ERR, "Unable to open OpenIPMI device"); - do_exit(NULL, EXIT_FAILURE); - } - - /* enable event message buffer */ - lprintf(LOG_DEBUG, "Enabling event message buffer"); - r = enable_event_msg_buffer(intf); - if (r < 0) { - lprintf(LOG_ERR, "Could not enable event message buffer"); - do_exit(intf, EXIT_FAILURE); - } - - /* enable OpenIPMI event receiver */ - lprintf(LOG_DEBUG, "Enabling event receiver"); - r = ioctl(intf->fd, IPMICTL_SET_GETS_EVENTS_CMD, &i); - if (r != 0) { - lperror(LOG_ERR, "Could not enable event receiver"); - do_exit(intf, EXIT_FAILURE); - } - - lprintf(LOG_NOTICE, "Waiting for events..."); + int r; for (;;) { - pfd.fd = intf->fd; /* wait on openipmi device */ - pfd.events = POLLIN; /* wait for input */ + pfd.fd = eintf->intf->fd; /* wait on openipmi device */ + pfd.events = POLLIN; /* wait for input */ r = poll(&pfd, 1, -1); switch (r) { @@ -330,14 +439,259 @@ int main(int argc, char ** argv) break; case -1: lperror(LOG_CRIT, "Unable to read from IPMI device"); - do_exit(intf, EXIT_FAILURE); - break; + return -1; default: - if (pfd.revents && POLLIN) - read_event(intf); + if (pfd.revents & POLLIN) + eintf->read(eintf); } } - lprintf(LOG_DEBUG, "Shutting down..."); - do_exit(intf, EXIT_SUCCESS); + return 0; +} +#endif /* IPMI_INTF_OPEN */ +/*************************************************************************/ + + +/*************************************************************************/ +/** SEL Watch Functions **/ +/*************************************************************************/ +static uint16_t +selwatch_get_count(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = IPMI_CMD_GET_SEL_INFO; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get SEL Info command failed"); + return 0; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get SEL Info command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return 0; + } + + return buf2short(rsp->data+1); +} + +static uint16_t +selwatch_get_lastid(struct ipmi_intf * intf) +{ + uint16_t next_id = 0; + uint16_t curr_id = 0; + struct sel_event_record evt; + + while (next_id != 0xffff) { + curr_id = next_id; + lprintf(LOG_DEBUG, "SEL Next ID: %04x", curr_id); + + next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt); + if (next_id == 0) { + /* + * usually next_id of zero means end but + * retry because some hardware has quirks + * and will return 0 randomly. + */ + next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt); + if (next_id == 0) + break; + } + } + + return curr_id; +} + +static int +selwatch_setup(struct ipmi_event_intf * eintf) +{ + /* save current sel record count */ + selwatch_count = selwatch_get_count(eintf->intf); + lprintf(LOG_DEBUG, "Current SEL count is %d", selwatch_count); + + /* save current last record ID */ + selwatch_lastid = selwatch_get_lastid(eintf->intf); + lprintf(LOG_DEBUG, "Current SEL lastid is %04x", selwatch_lastid); + + return 0; +} + +/* selwatch_check - check for waiting events + * + * this is done by reading sel info and comparing + * the sel count value to what we currently know + */ +static int +selwatch_check(struct ipmi_event_intf * eintf) +{ + uint16_t old_count = selwatch_count; + selwatch_count = selwatch_get_count(eintf->intf); + return (selwatch_count > old_count); +} + +static int +selwatch_read(struct ipmi_event_intf * eintf) +{ + uint16_t curr_id = 0; + uint16_t next_id = selwatch_lastid; + struct sel_event_record evt; + + while (next_id != 0xffff) { + curr_id = next_id; + lprintf(LOG_DEBUG, "SEL Next ID: %04x", curr_id); + + next_id = ipmi_sel_get_std_entry(eintf->intf, curr_id, &evt); + if (next_id == 0) { + /* + * usually next_id of zero means end but + * retry because some hardware has quirks + * and will return 0 randomly. + */ + next_id = ipmi_sel_get_std_entry(eintf->intf, curr_id, &evt); + if (next_id == 0) + break; + } + + if (curr_id != selwatch_lastid) + eintf->log(eintf, &evt); + } + + selwatch_lastid = curr_id; +} + +static int +selwatch_wait(struct ipmi_event_intf * eintf) +{ + for (;;) { + if (eintf->check(eintf) > 0) { + lprintf(LOG_DEBUG, "New Events"); + eintf->read(eintf); + } + sleep(selwatch_timeout); + } +} +/*************************************************************************/ + +int +ipmievd_main(struct ipmi_event_intf * eintf, int argc, char ** argv) +{ + int i, rc; + int daemon = 1; + + for (i = 0; i < argc; i++) { + if (strncasecmp(argv[i], "help", 4) == 0) { + ipmievd_usage(); + return 0; + } + if (strncasecmp(argv[i], "daemon", 6) == 0) { + daemon = 1; + } + else if (strncasecmp(argv[i], "nodaemon", 8) == 0) { + daemon = 0; + } + else if (strncasecmp(argv[i], "daemon=", 7) == 0) { + if (strncasecmp(argv[i]+7, "on", 2) == 0 || + strncasecmp(argv[i]+7, "yes", 3) == 0) + daemon = 1; + else if (strncasecmp(argv[i]+7, "off", 3) == 0 || + strncasecmp(argv[i]+7, "no", 2) == 0) + daemon = 0; + } + else if (strncasecmp(argv[i], "timeout=", 8) == 0) { + selwatch_timeout = strtoul(argv[i]+8, NULL, 0); + } + } + + if (daemon) + ipmi_start_daemon(); + + log_halt(); + log_init("ipmievd", daemon, verbose); + + /* generate SDR cache for fast lookups */ + lprintf(LOG_NOTICE, "Reading sensors..."); + ipmi_sdr_list_cache(eintf->intf); + lprintf(LOG_DEBUG, "Sensors cached"); + + /* call event handler setup routine */ + if (eintf->setup != NULL) { + rc = eintf->setup(eintf); + if (rc < 0) { + lprintf(LOG_ERR, "Error setting up Event Interface %s", eintf->name); + return -1; + } + } + + lprintf(LOG_NOTICE, "Waiting for events..."); + + /* now launch event wait loop */ + if (eintf->wait != NULL) { + rc = eintf->wait(eintf); + if (rc < 0) { + lprintf(LOG_ERR, "Error waiting for events!"); + return -1; + } + } + + return 0; +} + +int +ipmievd_sel_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + struct ipmi_event_intf * eintf; + + eintf = ipmi_event_intf_load("sel"); + if (eintf == NULL) { + lprintf(LOG_ERR, "Unable to load event interface"); + return -1; + } + + eintf->intf = intf; + + return ipmievd_main(eintf, argc, argv); +} + +int +ipmievd_open_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + struct ipmi_event_intf * eintf; + + /* only one interface works for this */ + if (strncmp(intf->name, "open", 4) != 0) { + lprintf(LOG_ERR, "Invalid Interface for OpenIPMI Event Handler: %s", intf->name); + return -1; + } + + eintf = ipmi_event_intf_load("open"); + if (eintf == NULL) { + lprintf(LOG_ERR, "Unable to load event interface"); + return -1; + } + + eintf->intf = intf; + + return ipmievd_main(eintf, argc, argv); +} + +struct ipmi_cmd ipmievd_cmd_list[] = { + { ipmievd_sel_main, "sel", "Poll SEL for notification of events" }, + { ipmievd_open_main, "open", "Use OpenIPMI for asyncronous notification of events" }, + { NULL } +}; + +int main(int argc, char ** argv) +{ + int rc; + + rc = ipmi_main(argc, argv, ipmievd_cmd_list, NULL); + + if (rc < 0) + exit(EXIT_FAILURE); + else + exit(EXIT_SUCCESS); }