Add IPMI event logging support to servicelog package by reading from a FIFO
created by the ipmievd daemon (part of ipmitool package). ipmilog daemon reads
events from this FIFO and logs them to the servicelog database through
servicelog APIs.

This version of patch uses ipmitool structure as the interface between
ipmievd and ipmilog utilties. From ipmitool structure, servicelog structure
is populated.

Signed-off-by: M. Mohan Kumar <mo...@in.ibm.com>
---
 configure.ac    |   10 ++-
 src/Makefile.am |    2 +-
 src/ipmilog.c   |  370 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 379 insertions(+), 3 deletions(-)
 create mode 100644 src/ipmilog.c

diff --git a/configure.ac b/configure.ac
index 261c4c7..bd6b34e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,20 +37,26 @@ VERSION=$GENERIC_VERSION
 # Checks for programs.
 AC_PROG_CC
 AC_PROG_INSTALL
+AC_PROG_CXX
+AC_PROG_LN_S
+AC_PROG_RANLIB
 
 # Checks for libraries.
 AC_CHECK_LIB([servicelog], [servicelog_open servicelog_close])
 
 # Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS([stdlib.h string.h unistd.h])
+AC_CHECK_HEADERS([stdlib.h string.h unistd.h fcntl.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 AC_TYPE_SIZE_T
+AC_TYPE_PID_T
 
 # Checks for library functions.
-AC_CHECK_FUNCS([memset strtol])
+AC_CHECK_FUNCS([memset strtol strerror fork])
+AC_FUNC_FORK()
+AC_FUNC_MALLOC()
 
 AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile servicelog.spec])
 AC_OUTPUT
diff --git a/src/Makefile.am b/src/Makefile.am
index 7b7f5f5..4d84409 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
 AM_CFLAGS = -Wall
 AM_LDFLAGS = -lservicelog
 
-bin_PROGRAMS = servicelog servicelog_notify log_repair_action
+bin_PROGRAMS = servicelog servicelog_notify log_repair_action ipmilog
 sbin_PROGRAMS = slog_common_event
 
 servicelog_SOURCES = servicelog.c
diff --git a/src/ipmilog.c b/src/ipmilog.c
new file mode 100644
index 0000000..5452d78
--- /dev/null
+++ b/src/ipmilog.c
@@ -0,0 +1,370 @@
+/**
+ * @file ipmilog.c
+ * @brief Program for getting IPMI events from ipmievd and logging them
+ *  to servicelog database
+ *
+ * Copyright (C) 2008  IBM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <poll.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <servicelog-1/servicelog.h>
+
+#define FIFO "/var/log/sfifo"
+#define MSG_SIZE 256
+#define REFCODE_SIZE 50
+
+int fifo, listen, run_daemon = 1;
+servicelog *ipmi;
+char prog[50];
+
+/* Taken from ipmitool/include/ipmitool/ipmi_sel.h */
+struct standard_spec_sel_rec{
+       uint32_t        timestamp;
+       uint16_t        gen_id;
+       uint8_t evm_rev;
+       uint8_t sensor_type;
+       uint8_t sensor_num;
+#if WORDS_BIGENDIAN
+       uint8_t event_dir  : 1;
+       uint8_t event_type : 7;
+#else
+       uint8_t event_type : 7;
+       uint8_t event_dir  : 1;
+#endif
+#define DATA_BYTE2_SPECIFIED_MASK 0xc0    /* event_data[0] bit mask */
+#define DATA_BYTE3_SPECIFIED_MASK 0x30    /* event_data[0] bit mask */
+#define EVENT_OFFSET_MASK         0x0f    /* event_data[0] bit mask */
+       uint8_t event_data[3];
+};
+
+#define SEL_OEM_TS_DATA_LEN            6
+#define SEL_OEM_NOTS_DATA_LEN          13
+struct oem_ts_spec_sel_rec{
+       uint32_t timestamp;
+       uint8_t manf_id[3];
+       uint8_t oem_defined[SEL_OEM_TS_DATA_LEN];
+};
+
+struct oem_nots_spec_sel_rec{
+       uint8_t oem_defined[SEL_OEM_NOTS_DATA_LEN];
+};
+
+struct sel_event_record {
+       uint16_t        record_id;
+       uint8_t record_type;
+       union{
+               struct standard_spec_sel_rec standard_type;
+               struct oem_ts_spec_sel_rec oem_ts_type;
+               struct oem_nots_spec_sel_rec oem_nots_type;
+       } sel_type;
+} __attribute__ ((packed));
+
+/* SEL Event record from ipmievd */
+struct sel_event_record_sl {
+       struct sel_event_record sl;
+       char desc[MSG_SIZE];
+       char type[REFCODE_SIZE];
+       uint8_t e_class;
+};
+
+void log_error(const char *string, ...);
+void log_info(const char *string, ...);
+void event_slog(struct sel_event_record_sl event);
+int get_ipmi_event(void);
+void cleanup(int signum);
+
+/**
+ * log_error
+ * @brief Print the error message to syslog or stderr
+ *
+ * @param string error message to print
+ */
+void
+log_error(const char *string, ...)
+{
+       va_list vlist;
+       char msg[256];
+
+       va_start(vlist, string);
+       vsnprintf(msg, MSG_SIZE, string, vlist);
+       va_end(vlist);
+
+       if (run_daemon)
+               syslog(LOG_ERR, "%s:%s", msg, strerror(errno));
+       else
+               fprintf(stderr, "%s:%s\n", msg, strerror(errno));
+
+}
+
+/**
+ * log_info
+ * @brief Print the message to syslog or stdout
+ *
+ * @param string message to print
+ */
+void
+log_info(const char *string, ...)
+{
+       va_list vlist;
+       char msg[256];
+
+       va_start(vlist, string);
+       vsnprintf(msg, MSG_SIZE, string, vlist);
+       va_end(vlist);
+
+       if (run_daemon)
+               syslog(LOG_INFO, "%s", msg);
+       else
+               printf("%s\n", msg);
+
+}
+
+/**
+ * cleanup
+ * @brief signal handler routine to cleanup while exiting
+ *
+ * @param signum signal number caught
+ */
+void
+cleanup(int signum)
+{
+       log_info("%s: exiting", prog);
+       servicelog_close(ipmi);
+       close(fifo);
+       exit(0);
+}
+
+/**
+ * strprocess
+ * @brief function to convert a string to uppercase and remove whitespaces
+ *
+ * @param string to be converted
+ */
+static inline
+char *strprocess(char *string)
+{
+       int i,j;
+       char *newstring;
+
+       newstring = malloc(strlen(string));
+       if (newstring == NULL)
+               return NULL;
+       for (i=0, j=0; i < strlen(string); i++)
+               if (!isspace(string[i]))
+                       newstring[j++] = toupper(string[i]);
+
+       newstring[j] = '\0';
+
+       return newstring;
+}
+
+/**
+ * event_slog
+ * @brief function to log the event to servicelog db
+ *
+ * @param ipmi_event event structure
+ */
+void
+event_slog(struct sel_event_record_sl ipmi_event)
+{
+       uint64_t id;
+       char *sdesc, *refcode;
+       struct sl_event *event;
+       struct sl_data_bmc *bmc_info;
+
+       if ((event = malloc(sizeof(struct sl_event))) == NULL) {
+               log_error("Can not allocate memory for event\n");
+               return;
+       }
+       if ((bmc_info = malloc(sizeof(struct sl_data_bmc))) == NULL) {
+               log_error("Can not allocate memory for bmc\n");
+               goto error1;
+       }
+       if ((sdesc = malloc(sizeof(char) * (strlen(ipmi_event.desc) + 1))) == 
NULL) {
+               log_error("Can not allocate memory for string desc\n");
+               goto error2;
+       }
+       if ((refcode = malloc(sizeof(char) * 255)) == NULL) {
+               log_error("Can not allocate memory for string refcode\n");
+               goto error3;
+       }
+
+       memset(event, 0, sizeof(struct sl_event));
+       memset(bmc_info, 0, sizeof(struct sl_data_bmc));
+       memset(sdesc, 0, strlen(ipmi_event.desc));
+       memset(refcode, 0, 255);
+
+       strcpy(refcode, "#");
+       strcat(refcode, strprocess(ipmi_event.type));
+
+       event->time_event = ipmi_event.sl.sel_type.standard_type.timestamp;
+       event->type = SL_TYPE_BMC;
+       event->severity = SL_SEV_EVENT;
+       event->description = sdesc;
+       strcpy(event->description,ipmi_event.desc);
+       event->refcode = refcode;
+
+       if(ipmi_event.sl.sel_type.standard_type.event_type == 1) {
+               /* Threshold event */
+               event->serviceable = 1;
+               event->predictive = 1;
+               event->disposition = SL_DISP_RECOVERABLE;
+       } else if((ipmi_event.sl.sel_type.standard_type.event_type >= 2 &&
+               ipmi_event.sl.sel_type.standard_type.event_type <= 0xc) ||
+               ipmi_event.sl.sel_type.standard_type.event_type == 0x6f) {
+               /* Discrete event */
+               event->serviceable = 1;
+               event->disposition = SL_DISP_RECOVERABLE;
+       }
+
+       event->addl_data = bmc_info;
+       bmc_info->sel_id = ipmi_event.sl.record_id;
+       bmc_info->sel_type = ipmi_event.sl.record_type;
+       bmc_info->generator = ipmi_event.sl.sel_type.standard_type.gen_id;
+       bmc_info->version = ipmi_event.sl.sel_type.standard_type.evm_rev;
+       bmc_info->sensor_type = 
ipmi_event.sl.sel_type.standard_type.sensor_type;
+       bmc_info->sensor_number = 
ipmi_event.sl.sel_type.standard_type.sensor_num;
+       bmc_info->event_class = ipmi_event.e_class;
+       bmc_info->event_type = ipmi_event.sl.sel_type.standard_type.event_type;
+       bmc_info->direction = ipmi_event.sl.sel_type.standard_type.event_dir;
+
+       if (servicelog_event_log(ipmi, event, &id)) {
+               log_error("servicelog error: %s", servicelog_error(ipmi));
+               goto error4;
+       }
+       servicelog_event_free(event);
+       return;
+
+error4:
+       free(refcode);
+error3:
+       free(sdesc);
+error2:
+       free(bmc_info);
+error1:
+       free(event);
+
+       return;
+}
+
+/**
+ * get_ipmi_event
+ * @brief function reads from the ipmi event FIFO
+ */
+int
+get_ipmi_event(void)
+{
+       int rc;
+       struct pollfd fd;
+       struct sel_event_record_sl ipmi_event;
+
+       memset(&fd, 0, sizeof(fd));
+       fd.fd = fifo;
+       fd.events = POLLIN;
+
+       do {
+               poll(&fd, 1, -1);
+               switch (fd.revents) {
+                       case POLLHUP:
+                               log_error("pollhup");
+                               break;
+                       case POLLERR:
+                               log_error("pollerr");
+                               break;
+                       case POLLNVAL:
+                               log_error("pollnval");
+                               break;
+               }
+
+               rc = read(fifo, &ipmi_event, sizeof(ipmi_event));
+               if (rc == 0)
+                       return 0;
+               else if (rc < 0) {
+                       log_error("reading from fifo");
+                       return 0;
+               }
+
+               event_slog(ipmi_event);
+
+       } while (1);
+
+       return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+       int rc;
+       struct sigaction handler;
+
+       if (argc > 1) {
+               if(!strcasecmp(argv[1], "nodaemon"))
+                       run_daemon = 0;
+               else {
+                       fprintf(stderr, "usage: %s [nodaemon]\n", argv[0]);
+                       return -1;
+               }
+       }
+
+       fifo = open(FIFO, O_RDONLY | O_NONBLOCK);
+
+       if (fifo < 0) {
+               fprintf(stderr, "opening fifo %s", FIFO);
+               return -1;
+       }
+
+       rc = servicelog_open(&ipmi, 0);
+       if (rc) {
+               fprintf(stderr, "Error opening servicelog: %s\n", strerror(rc));
+               exit(2);
+       }
+
+       if (run_daemon)
+               daemon(0,0);
+
+       memset(&handler, 0, sizeof(handler));
+       handler.sa_handler = cleanup;
+       if (sigaction(SIGTERM, &handler, NULL) < 0)
+               log_error("signal");
+
+       if (!run_daemon)
+               if (sigaction(SIGINT, &handler, NULL) < 0)
+                       log_error("signal");
+
+       strcpy(prog, argv[0]);
+
+       log_info("%s: started", prog);
+       get_ipmi_event();
+       log_info("%s: exiting", prog);
+       servicelog_close(ipmi);
+       close(fifo);
+       return 0;
+}
-- 
1.6.0.4


------------------------------------------------------------------------------
_______________________________________________
Ipmitool-devel mailing list
Ipmitool-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ipmitool-devel

Reply via email to