diff options
Diffstat (limited to 'src/ipmievd.c')
-rw-r--r-- | src/ipmievd.c | 881 |
1 files changed, 881 insertions, 0 deletions
diff --git a/src/ipmievd.c b/src/ipmievd.c new file mode 100644 index 0000000..f940579 --- /dev/null +++ b/src/ipmievd.c @@ -0,0 +1,881 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> + +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined(HAVE_SYS_IOCCOM_H) +# include <sys/ioccom.h> +#endif + +#ifdef HAVE_PATHS_H +# include <paths.h> +#endif + +#ifndef _PATH_VARRUN +# define _PATH_VARRUN "/var/run/" +#endif + +#ifdef IPMI_INTF_OPEN +# if defined(HAVE_OPENIPMI_H) +# if defined(HAVE_LINUX_COMPILER_H) +# include <linux/compiler.h> +# endif +# include <linux/ipmi.h> +# elif defined(HAVE_FREEBSD_IPMI_H) +# include <sys/ipmi.h> +# else +# include "plugins/open/open.h" +# endif +# include <sys/poll.h> +#endif /* IPMI_INTF_OPEN */ + +#include <ipmitool/helper.h> +#include <ipmitool/log.h> +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_sel.h> +#include <ipmitool/ipmi_sdr.h> +#include <ipmitool/ipmi_strings.h> +#include <ipmitool/ipmi_main.h> + +#define WARNING_THRESHOLD 80 +#define DEFAULT_PIDFILE _PATH_VARRUN "ipmievd.pid" +char pidfile[64]; + +/* global variables */ +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_pctused = 0; /* current percent usage in the SEL */ +int selwatch_overflow = 0; /* SEL overflow */ +int selwatch_timeout = 10; /* default to 10 seconds */ + +/* event interface definition */ +struct ipmi_event_intf { + char name[16]; + char desc[128]; + char prefix[72]; + 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; +}; + +/* Data from SEL we are interested in */ +typedef struct sel_data { + uint16_t entries; + int pctused; + int overflow; +} sel_data; + +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 struct ipmi_event_intf openipmi_event_intf = { + name: "open", + desc: "OpenIPMI asyncronous notification of events", + prefix: "", + 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 +}; + +/*************************************************************************/ + +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 int +compute_pctfull(uint16_t entries, uint16_t freespace) +{ + int pctfull = 0; + + if (entries) { + entries *= 16; + freespace += entries; + pctfull = (int)(100 * ( (double)entries / (double)freespace )); + } + return pctfull; +} + + +static void +log_event(struct ipmi_event_intf * eintf, struct sel_event_record * evt) +{ + char *desc; + const char *type; + struct sdr_record_list * sdr; + 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, "%sLinux kernel panic: %.11s", + eintf->prefix, (char *) evt + 5); + return; + } + else if (evt->record_type >= 0xc0) { + lprintf(LOG_NOTICE, "%sIPMI Event OEM Record %02x", + eintf->prefix, evt->record_type); + return; + } + + type = ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, + evt->sel_type.standard_type.event_data[0]); + + ipmi_get_event_desc(intf, evt, &desc); + + sdr = ipmi_sdr_find_sdr_bynumtype(intf, evt->sel_type.standard_type.gen_id, evt->sel_type.standard_type.sensor_num, + evt->sel_type.standard_type.sensor_type); + + if (sdr == NULL) { + /* could not find matching SDR record */ + if (desc) { + lprintf(LOG_NOTICE, "%s%s sensor - %s", + eintf->prefix, type, desc); + free(desc); + desc = NULL; + } else { + lprintf(LOG_NOTICE, "%s%s sensor %02x", + eintf->prefix, type, + evt->sel_type.standard_type.sensor_num); + } + return; + } + + switch (sdr->type) { + case SDR_RECORD_TYPE_FULL_SENSOR: + if (evt->sel_type.standard_type.event_type == 1) { + /* + * Threshold Event + */ + + /* trigger reading in event data byte 2 */ + if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) { + trigger_reading = sdr_convert_sensor_reading( + sdr->record.full, evt->sel_type.standard_type.event_data[1]); + } + + /* trigger threshold in event data byte 3 */ + if (((evt->sel_type.standard_type.event_data[0] >> 4) & 3) == 1) { + threshold_reading = sdr_convert_sensor_reading( + sdr->record.full, evt->sel_type.standard_type.event_data[2]); + } + + lprintf(LOG_NOTICE, "%s%s sensor %s %s %s (Reading %.*f %s Threshold %.*f %s)", + eintf->prefix, + type, + sdr->record.full->id_string, + desc ? : "", + (evt->sel_type.standard_type.event_dir + ? "Deasserted" : "Asserted"), + (trigger_reading==(int)trigger_reading) ? 0 : 2, + trigger_reading, + ((evt->sel_type.standard_type.event_data[0] & 0xf) % 2) ? ">" : "<", + (threshold_reading==(int)threshold_reading) ? 0 : 2, + threshold_reading, + ipmi_sdr_get_unit_string(sdr->record.common->unit.pct, + sdr->record.common->unit.modifier, + sdr->record.common->unit.type.base, + sdr->record.common->unit.type.modifier)); + } + else if ((evt->sel_type.standard_type.event_type >= 0x2 && evt->sel_type.standard_type.event_type <= 0xc) || + (evt->sel_type.standard_type.event_type == 0x6f)) { + /* + * Discrete Event + */ + lprintf(LOG_NOTICE, "%s%s sensor %s %s %s", + eintf->prefix, type, + sdr->record.full->id_string, desc ? : "", + (evt->sel_type.standard_type.event_dir + ? "Deasserted" : "Asserted")); + if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) { + /* previous state and/or severity in event data byte 2 */ + } + } + else if (evt->sel_type.standard_type.event_type >= 0x70 && evt->sel_type.standard_type.event_type <= 0x7f) { + /* + * OEM Event + */ + lprintf(LOG_NOTICE, "%s%s sensor %s %s %s", + eintf->prefix, type, + sdr->record.full->id_string, desc ? : "", + (evt->sel_type.standard_type.event_dir + ? "Deasserted" : "Asserted")); + } + break; + + case SDR_RECORD_TYPE_COMPACT_SENSOR: + lprintf(LOG_NOTICE, "%s%s sensor %s - %s %s", + eintf->prefix, type, + sdr->record.compact->id_string, desc ? : "", + (evt->sel_type.standard_type.event_dir + ? "Deasserted" : "Asserted")); + break; + + default: + lprintf(LOG_NOTICE, "%s%s sensor - %s", + eintf->prefix, type, + evt->sel_type.standard_type.sensor_num, desc ? : ""); + break; + } + + if (desc) { + free(desc); + desc = NULL; + } +} +/*************************************************************************/ + + +/*************************************************************************/ +/** 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; + uint8_t bmc_global_enables; + + /* we must read/modify/write bmc global enables */ + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x2f; /* Get BMC Global Enables */ + + rsp = intf->sendrecv(intf, &req); + 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; + } + + bmc_global_enables = rsp->data[0] | 0x04; + req.msg.cmd = 0x2e; /* Set BMC Global Enables */ + req.msg.data = &bmc_global_enables; + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); + 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; + } + + lprintf(LOG_DEBUG, "BMC Event Message Buffer enabled"); + + return 0; +} + +static int +openipmi_setup(struct ipmi_event_intf * eintf) +{ + int i, r; + + /* 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 int +openipmi_read(struct ipmi_event_intf * eintf) +{ + struct ipmi_addr addr; + struct ipmi_recv recv; + uint8_t data[80]; + int rv; + + recv.addr = (unsigned char *) &addr; + recv.addr_len = sizeof(addr); + recv.msg.data = data; + recv.msg.data_len = sizeof(data); + + rv = ioctl(eintf->intf->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv); + if (rv < 0) { + switch (errno) { + case EINTR: + return 0; /* abort */ + case EMSGSIZE: + recv.msg.data_len = sizeof(data); /* truncated */ + break; + default: + lperror(LOG_ERR, "Unable to receive IPMI message"); + return -1; + } + } + + if (!recv.msg.data || recv.msg.data_len == 0) { + lprintf(LOG_ERR, "No data in event"); + return -1; + } + if (recv.recv_type != IPMI_ASYNC_EVENT_RECV_TYPE) { + lprintf(LOG_ERR, "Type %x is not an event", recv.recv_type); + return -1; + } + + lprintf(LOG_DEBUG, "netfn:%x cmd:%x ccode:%d", + recv.msg.netfn, recv.msg.cmd, recv.msg.data[0]); + + eintf->log(eintf, (struct sel_event_record *)recv.msg.data); + + return 0; +} + +static int +openipmi_wait(struct ipmi_event_intf * eintf) +{ + struct pollfd pfd; + int r; + + for (;;) { + pfd.fd = eintf->intf->fd; /* wait on openipmi device */ + pfd.events = POLLIN; /* wait for input */ + r = poll(&pfd, 1, -1); + + switch (r) { + case 0: + /* timeout is disabled */ + break; + case -1: + lperror(LOG_CRIT, "Unable to read from IPMI device"); + return -1; + default: + if (pfd.revents & POLLIN) + eintf->read(eintf); + } + } + + return 0; +} +#endif /* IPMI_INTF_OPEN */ +/*************************************************************************/ + + +/*************************************************************************/ +/** SEL Watch Functions **/ +/*************************************************************************/ +static int +selwatch_get_data(struct ipmi_intf * intf, struct sel_data *data) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint16_t freespace; + + 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; + } + + freespace = buf2short(rsp->data + 3); + data->entries = buf2short(rsp->data + 1); + data->pctused = compute_pctfull (data->entries, freespace); + data->overflow = rsp->data[13] & 0x80; + + lprintf(LOG_DEBUG, "SEL count is %d", data->entries); + lprintf(LOG_DEBUG, "SEL freespace is %d", freespace); + lprintf(LOG_DEBUG, "SEL Percent Used: %d%%\n", data->pctused); + lprintf(LOG_DEBUG, "SEL Overflow: %s", data->overflow ? "true" : "false"); + + return 1; +} + +static uint16_t +selwatch_get_lastid(struct ipmi_intf * intf) +{ + int next_id = 0; + uint16_t curr_id = 0; + struct sel_event_record evt; + + if (selwatch_count == 0) + return 0; + + 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) + break; + 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; + } + } + + lprintf(LOG_DEBUG, "SEL lastid is %04x", curr_id); + + return curr_id; +} + +static int +selwatch_setup(struct ipmi_event_intf * eintf) +{ + struct sel_data data; + + /* save current sel record count */ + if (selwatch_get_data(eintf->intf, &data)) { + selwatch_count = data.entries; + selwatch_pctused = data.pctused; + selwatch_overflow = data.overflow; + 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); + /* display alert/warning immediatly as startup if relevant */ + if (selwatch_pctused >= WARNING_THRESHOLD) { + lprintf(LOG_WARNING, "SEL buffer used at %d%%, please consider clearing the SEL buffer", selwatch_pctused); + } + if (selwatch_overflow) { + lprintf(LOG_ALERT, "SEL buffer overflow, no SEL message can be logged until the SEL buffer is cleared"); + } + + return 1; + } + + lprintf(LOG_ERR, "Unable to retrieve SEL data"); + 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; + int old_pctused = selwatch_pctused; + int old_overflow = selwatch_overflow; + struct sel_data data; + + if (selwatch_get_data(eintf->intf, &data)) { + selwatch_count = data.entries; + selwatch_pctused = data.pctused; + selwatch_overflow = data.overflow; + if (old_overflow && !selwatch_overflow) { + lprintf(LOG_NOTICE, "SEL overflow is cleared"); + } else if (!old_overflow && selwatch_overflow) { + lprintf(LOG_ALERT, "SEL buffer overflow, no new SEL message will be logged until the SEL buffer is cleared"); + } + if ((selwatch_pctused >= WARNING_THRESHOLD) && (selwatch_pctused > old_pctused)) { + lprintf(LOG_WARNING, "SEL buffer is %d%% full, please consider clearing the SEL buffer", selwatch_pctused); + } + if (selwatch_count == 0) { + lprintf(LOG_DEBUG, "SEL count is 0 (old=%d), resetting lastid to 0", old_count); + selwatch_lastid = 0; + } else if (selwatch_count < old_count) { + selwatch_lastid = selwatch_get_lastid(eintf->intf); + lprintf(LOG_DEBUG, "SEL count lowered, new SEL lastid is %04x", selwatch_lastid); + } + } + return (selwatch_count > old_count); +} + +static int +selwatch_read(struct ipmi_event_intf * eintf) +{ + uint16_t curr_id = 0; + int next_id = selwatch_lastid; + struct sel_event_record evt; + + if (selwatch_count == 0) + return -1; + + while (next_id != 0xffff) { + curr_id = next_id; + lprintf(LOG_DEBUG, "SEL Read ID: %04x", curr_id); + + next_id = ipmi_sel_get_std_entry(eintf->intf, curr_id, &evt); + if (next_id < 0) + break; + 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); + else if (curr_id == 0) + eintf->log(eintf, &evt); + } + + selwatch_lastid = curr_id; + return 0; +} + +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); + } + return 0; +} +/*************************************************************************/ + +static void +ipmievd_cleanup(int signal) +{ + struct stat st1; + + if (lstat(pidfile, &st1) == 0) { + /* cleanup daemon pidfile */ + (void)unlink(pidfile); + } + + exit(EXIT_SUCCESS); +} + +int +ipmievd_main(struct ipmi_event_intf * eintf, int argc, char ** argv) +{ + int i, rc; + int daemon = 1; + struct sigaction act; + + memset(pidfile, 0, 64); + sprintf(pidfile, "%s%d", DEFAULT_PIDFILE, eintf->intf->devnum); + lprintf(LOG_NOTICE, "ipmievd: using pidfile %s", pidfile); + + 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) { + if ( (str2int(argv[i]+8, &selwatch_timeout) != 0) || + selwatch_timeout < 0) { + lprintf(LOG_ERR, "Invalid input given or out of range for time-out."); + return (-1); + } + } + else if (strncasecmp(argv[i], "pidfile=", 8) == 0) { + memset(pidfile, 0, 64); + strncpy(pidfile, argv[i]+8, + __min(strlen((const char *)(argv[i]+8)), 63)); + } + } + + /* + * We need to open interface before forking daemon + * so error messages are not lost to syslog and + * return code is successfully returned to initscript + */ + if (eintf->intf->open(eintf->intf) < 0) { + lprintf(LOG_ERR, "Unable to open interface"); + return -1; + } + + if (daemon) { + FILE *fp; + struct stat st1; + + if (lstat(pidfile, &st1) == 0) { + /* PID file already exists -> exit. */ + lprintf(LOG_ERR, "PID file '%s' already exists.", pidfile); + lprintf(LOG_ERR, "Perhaps another instance is already running."); + return (-1); + } + + ipmi_start_daemon(eintf->intf); + + umask(022); + fp = ipmi_open_file_write(pidfile); + if (fp == NULL) { + /* Failed to get fp on PID file -> exit. */ + log_halt(); + log_init("ipmievd", daemon, verbose); + lprintf(LOG_ERR, + "Failed to open PID file '%s' for writing. Check file permission.", + pidfile); + exit(EXIT_FAILURE); + } + fprintf(fp, "%d\n", (int)getpid()); + fclose(fp); + } + + /* register signal handler for cleanup */ + act.sa_handler = ipmievd_cleanup; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + sigaction(SIGINT, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGTERM, &act, NULL); + + 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; + + if (intf->session != NULL) { + snprintf(eintf->prefix, + strlen((const char *)intf->session->hostname) + 3, + "%s: ", intf->session->hostname); + } + + 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[] = { +#ifdef IPMI_INTF_OPEN + { ipmievd_open_main, "open", "Use OpenIPMI for asyncronous notification of events" }, +#endif + { ipmievd_sel_main, "sel", "Poll SEL for 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); +} |