summaryrefslogtreecommitdiff
path: root/util/igetevent.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-06 18:04:32 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-06 18:04:32 +0200
commita7f89980e5b3f4b9a74c70dbc5ffe8aabd28be28 (patch)
tree41c4deec1fdfbafd7821b4ca7a9772ac0abd92f5 /util/igetevent.c
Imported Upstream version 2.9.3upstream/2.9.3
Diffstat (limited to 'util/igetevent.c')
-rw-r--r--util/igetevent.c1439
1 files changed, 1439 insertions, 0 deletions
diff --git a/util/igetevent.c b/util/igetevent.c
new file mode 100644
index 0000000..6e2fe27
--- /dev/null
+++ b/util/igetevent.c
@@ -0,0 +1,1439 @@
+/*
+ * igetevent.c
+ *
+ * This utility waits for IPMI Event Messages.
+ * Some server management functions want to trigger custom actions or
+ * alerts when IPMI hardware-related events occur, but do not want to
+ * track all events, just newly occurring events.
+ * The IPMI events also include BIOS events such as Memory and POST errors,
+ * which would not be captured by reading the IPMI sensors.
+ * This utility waits a specified timeout period for any events, and
+ * returns interpreted output for each event. It is designed as a
+ * scriptable command-line utility, but if the timeout is infinite
+ * (-t 0), then this code could be used for a sample service as well.
+ *
+ * There are several methods to do this which are implemented here.
+ * The SEL method (-s):
+ * This method polls the SEL once a second, keeps track of the last
+ * SEL event read, and only new events are processed. This ensures
+ * that in a series of rapid events, all events are received in order,
+ * however, some transition-to-OK events may not be configured to
+ * write to the SEL on certain platforms.
+ * This method is used if getevent -s is specified.
+ * The ReadEventMessageBuffer method (-m getmessage option):
+ * This uses an IPMI Message Buffer in the BMC firmware to read
+ * each new event. This receives any event, but if two events
+ * occur nearly simultaneously, only the most recent of the two
+ * will be returned with this method. An example of simultaneous
+ * events might be, if a fan stops/fails, both the non-critical
+ * and critical fan threshold events would occur at that time.
+ * This is the default method for getevent. It would be used
+ * locally with the Intel IMB driver or with direct/driverless.
+ * The OpenIPMI custom method (-m getmessage_mv option if DRV_MV):
+ * Different IPMI drivers may have varying behavior. For instance,
+ * the OpenIPMI driver uses the IPMI GetMessage commands internally
+ * and does not allow client programs to use those commands. It has
+ * its own custom mechanism, see getevent_mv().
+ * This method is used locally if the OpenIPMI driver is detected.
+ * The Async Event method (-a):
+ * This only gets certain Asynchronous events, like a shutdown
+ * request from the BMC to an SMS OS service, and get_software_id.
+ * This is supported for Intel IMB driver and OpenIPMI driver only.
+ * This method is only used locally if getevent option -a is used,
+ * and if either MV (openipmi) or IMB driver is loaded.
+ * The ipmiutil_asy init script controls the getevent -a service.
+ * (see DO_ASYNC compile flag comments)
+ *
+ * Author: Andy Cress arcress at users.sourceforge.net
+ * Copyright (c) 2005-2006 Intel Corporation.
+ * Copyright (c) 2009 Kontron America, Inc.
+ *
+ * 02/11/05 Andy Cress - created
+ * 05/18/05 Andy Cress - modified bmc_enable bits
+ * 05/26/05 Andy Cress - added call to decode_sel_entry
+ * 09/09/05 Andy Cress - added sensor_type filtering & return type.
+ * 03/16/05 Andy Cress - added loop, and -o for frunOnce
+ * 06/27/06 Andy Cress 1.1 - specific message for cc=0x80 (no data)
+ * 07/18/06 Andy Cress 1.1 - added getevent_mv, etc.
+ * 07/26/06 Andy Cress 1.1 - added msgout() routine for fflush
+ * 08/08/06 Andy Cress 1.2 - added -s for SEL method
+ * 08/08/06 Andy Cress 1.2 - added -s for SEL method
+ * 08/22/06 Andy Cress 1.3 - direct IOs added with ipmiutil-1.7.5
+ * 09/13/06 Andy Cress 1.4 - handle empty SEL (0xCB),
+ * call syncevent_sel after every new event.
+ * 09/21/07 Andy Cress 1.21 - implemented IMB Async method for remote
+ * OS shutdown via SMS requests.
+ */
+/*M*
+Copyright (c) 2009 Kontron America, Inc.
+Copyright (c) 2013 Andy Cress <arcress at users.sourceforge.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ a.. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ b.. Redistributions 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.
+ c.. Neither the name of Kontron nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *M*/
+#ifdef WIN32
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "getopt.h"
+#elif defined(DOS)
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include "getopt.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#if defined(HPUX)
+/* getopt is defined in stdio.h */
+#elif defined(MACOS)
+/* getopt is defined in unistd.h */
+#include <unistd.h>
+#else
+#include <getopt.h>
+#include <unistd.h>
+#endif
+#include <pthread.h>
+#include <sys/utsname.h>
+#endif
+#include <string.h>
+#ifdef SOLARIS
+/* Solaris */
+#define HandleType long
+#elif WIN32
+#include "imb_api.h"
+#define DO_ASYNC 1
+#elif LINUX
+#define LINUX 1
+#include "imb_api.h"
+#define DO_ASYNC 1
+#define DO_MVL 1
+#elif BSD
+#define DO_MVL 1
+#define HandleType long
+#else
+/* other OS */
+#define HandleType long
+#endif
+#include "ipmicmd.h"
+
+#define THREADS_OK 1
+#define IMBPTIMEOUT 200 /*200 ms*/
+// #define IPMB_CHANNEL 0x00
+// #define LAN_CHANNEL 0x02
+#define ulong unsigned long
+#define uint unsigned int
+#define ushort unsigned short
+#define uchar unsigned char
+
+#define CMD_GET_SOFTWARE_ID 0x00
+#define CMD_SMS_OS_REQUEST 0x10
+
+extern int decode_sel_entry(uchar *evt, char *obuf, int sz); /*see ievents.c*/
+extern void set_sel_opts(int sensdesc, int canon, void *sdrs, char fdbg, char utc); /* ievents.c */
+extern char *get_sensor_type_desc(uchar stype); /*see ievents.c*/
+extern int write_syslog(char *msg); /*see isel.c*/
+extern char *show_driver_type(int idx); /*see ipmicmd.h*/
+extern int get_sdr_cache(uchar **pret); /*see isensor.c*/
+extern void free_sdr_cache(uchar *pret); /*see isensor.c*/
+
+/*
+ * Global variables
+ */
+static char * progname = "igetevent";
+static char * progver = "2.93";
+static char fdebug = 0;
+static char fipmilan = 0;
+static char frunonce = 0;
+static char futc = 0;
+static char fAsync = 0;
+static char fAsyncOK = 0; /*=1 if drvtype detected for it*/
+static char fAsyncNOP = 0; /*=1 if skip Async actions*/
+static char fbackground = 0;
+static char frunscript = 0;
+static char fcanonical = 0;
+static char fsettime = 0; /* =1 if timeout is set by -t */
+static uchar evt_stype = 0xff; /* event sensor type, 0xff = get any events */
+static uchar evt_snum = 0xff; /* event sensor num, 0xff = get any events */
+static int timeout = 120; /* 120 seconds default timeout */
+static int wait_interval = 1; /* 1 second between calls */
+static FILE *fdout = NULL;
+static char *run_script = NULL;
+static uchar ipmi_maj = 0;
+static uchar ipmi_min = 0;
+static HandleType imb_handle = 0;
+static int drvtype = 0; /* driver_type from ipmicmd.h: 1=Intel_imb, 3=MV_OpenIPMI */
+static int vend_id = 0;
+static int prod_id = 0;
+static char fselevts = 0;
+static char fmsgevts = 0;
+static ushort sel_recid = 0;
+static uint sel_time = 0;
+static uchar sms_sa = 0x81;
+static uchar *sdrs = NULL;
+#define LAST_REC 0xFFFF
+#ifdef WIN32
+#define IDXFILE "ipmi_evt.idx"
+static char idxfile[80] = IDXFILE;
+static char idxfile2[80] = "c:\\ipmi_evt.idx";
+static char outfile[80] = "c:\\ipmiutil_evt.log";
+#define SHUTDOWN_CMD "shutdown -s -d p:01:01 -t 10"
+#define REBOOT_CMD "shutdown -r -d p:01:01 -t 10"
+#else
+static char idxfile[80] = "/var/lib/ipmiutil/evt.idx";
+static char idxfile2[80] = "/usr/share/ipmiutil/evt.idx";
+static char outfile[80] = "/var/log/ipmiutil_evt.log";
+#define SHUTDOWN_CMD "init 0" // or shutdown now
+#define REBOOT_CMD "init 6"
+#endif
+#ifdef METACOMMAND
+extern FILE *fpdbg; /*from ipmicmd.c*/
+extern FILE *fperr; /*from ipmicmd.c*/
+#endif
+/* prototypes */
+static void iclose(void);
+static void ievt_siginit(void);
+static void ievt_cleanup(void);
+
+#define METHOD_UNKNOWN 0
+#define METHOD_SEL_EVTS 1
+#define METHOD_MSG_GET 2
+#define METHOD_MSG_MV 3
+#define METHOD_ASYNC_MV 4
+#define METHOD_ASYNC_IMB 5
+static char *methodstr[6] = {
+ "unknown",
+ "SEL_events",
+ "GetMessage",
+ "GetMessage_mv",
+ "Async_mv",
+ "Async_imb" };
+
+static int do_wait(int nsec)
+{
+ int rv = 0;
+ if (nsec > 0) os_usleep(nsec,0); /*declared in ipmicmd.h*/
+ return(rv);
+}
+
+static int get_event_receiver(uchar *sa, uchar *lun)
+{
+ uchar rdata[30];
+ int rlen;
+ uchar ccode;
+ int ret;
+
+ rlen = 2;
+#if 0
+ ret = ipmi_cmdraw( 0x01,NETFN_SEVT,BMC_SA,PUBLIC_BUS,BMC_LUN,
+ idata,0, rdata,&rlen,&ccode, fdebug);
+#endif
+ ret = ipmi_cmd(GET_EVENT_RECEIVER,NULL,0, rdata,&rlen,&ccode, 0);
+ if (ret == 0 && ccode != 0) ret = ccode;
+ if (ret == 0) {
+ *sa = rdata[0];
+ *lun = rdata[1];
+ }
+ return(ret);
+}
+
+static int get_msg_flags(uchar *flags)
+{
+ uchar rdata[8];
+ int rlen = 1;
+ uchar ccode;
+ int ret;
+ ret = ipmi_cmdraw( 0x31,NETFN_APP,BMC_SA,PUBLIC_BUS,BMC_LUN,
+ NULL,0, rdata,&rlen,&ccode, fdebug);
+ if (ret == 0 && ccode != 0) ret = ccode;
+ if ((ret == 0) && (flags != NULL)) *flags = rdata[0];
+ return(ret);
+}
+
+static int set_bmc_enables(uchar enab)
+{
+ uchar idata[8];
+ uchar rdata[30];
+ int rlen;
+ uchar ccode;
+ int ret;
+
+ idata[0] = enab;
+ rlen = 1;
+ ret = ipmi_cmdraw( 0x2E,NETFN_APP,BMC_SA,PUBLIC_BUS,BMC_LUN,
+ idata,1, rdata,&rlen,&ccode, fdebug);
+ if (ret == 0 && ccode != 0) ret = ccode;
+ return(ret);
+}
+
+static int get_bmc_enables(uchar *enab)
+{
+ uchar rdata[30];
+ int rlen;
+ uchar ccode;
+ int ret;
+
+ rlen = 1;
+ ret = ipmi_cmdraw( 0x2F,NETFN_APP,BMC_SA,PUBLIC_BUS,BMC_LUN,
+ NULL,0, rdata,&rlen,&ccode, fdebug);
+ if (ret == 0 && ccode != 0) ret = ccode;
+
+ if (ret == 0) *enab = rdata[0];
+ return(ret);
+}
+
+/*
+ * msgout
+ * wrapper for printf() to include fflush
+ */
+void msgout(char *pattn, ...)
+{
+ va_list arglist;
+
+ if (fdout == NULL) return;
+ va_start( arglist, pattn );
+ vfprintf( fdout, pattn, arglist );
+ va_end( arglist );
+ fflush( fdout );
+}
+
+#ifdef DO_ASYNC
+/* The DO_ASYNC flag enables the IMB Async Message method via get_imb_event.
+ * This requires the Intel IMB driver, and is used only for remote shutdown
+ * and software ID events. */
+
+/* The LANDesk library has the same function names as the imbapi.c */
+#ifdef LINK_LANDESK
+#define StartAsyncMesgPoll ia_StartAsyncMesgPoll
+#define SendAsyncImbpRequest ia_SendAsyncImbpRequest
+#define GetAsyncImbpMessage ia_GetAsyncImbpMessage
+#define GetAsyncImbpMessage_Ex ia_GetAsyncImbpMessage_Ex
+#define IsAsyncMessageAvailable ia_IsAsyncMessageAvailable
+#define RegisterForImbAsyncMessageNotification ia_RegisterForImbAsyncMessageNotification
+#define UnRegisterForImbAsyncMessageNotification ia_UnRegisterForImbAsyncMessageNotification
+#define SendTimedLanMessageResponse_Ex ia_SendTimedLanMessageResponse_Ex
+#define SendTimedEmpMessageResponse_Ex ia_SendTimedEmpMessageResponse_Ex
+#endif /*endif LINK_LANDESK*/
+
+typedef struct {
+ uchar rsSa;
+ uchar nfLn;
+ uchar cSum1;
+ uchar rqSa;
+ uchar seqLn;
+ uchar cmd;
+ uchar data[1];
+} AsyImbPacket;
+
+#ifdef THREADS_OK
+ char message[32];
+#ifdef WIN32
+ HANDLE threadid = NULL;
+#else
+ pthread_t threadid = 0;
+#endif
+#endif
+
+#ifdef WIN32
+#define ThreadRType DWORD
+ThreadRType WINAPI pollThread( LPVOID p)
+#else
+#define ThreadRType void *
+ThreadRType pollThread(void *p)
+#endif
+{
+ int i;
+ int ret, limit;
+#ifdef THREADS_OK
+ limit = 0;
+#else
+ limit = 30;
+#endif
+ for (i = 0; (limit == 0) || (i < limit); i++)
+ {
+ ret = StartAsyncMesgPoll();
+ if (fdebug && i < 5)
+ msgout("StartAsyncMesgPoll [%d] ret = %d\n",i,ret);
+ // os_usleep(0,5000); /* poll interval 5 msec */
+ os_usleep(1,0); /* poll interval 1 sec */
+ }
+ return((ThreadRType)0);
+}
+
+static int GetBmcLanChannel(uchar *chan)
+{
+ int ret = 0;
+ int j;
+ int rlen;
+ uchar iData[2];
+ uchar rData[10];
+ uchar cc;
+ uchar mtype;
+ uchar chn = 1;
+
+ if (vend_id == VENDOR_INTEL) {
+ if (prod_id == 0x000C || prod_id == 0x001B) {
+ *chan = 7;
+ return(ret);
+ }
+ }
+ for (j = 1; j < 12; j++) {
+ rlen = sizeof(rData);
+ iData[0] = (uchar)j; /*channel #*/
+ memset(rData,0,9); /*initialize recv data*/
+ ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug);
+ if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */
+ continue;
+ if (ret != 0) {
+ if (fdebug) printf("get_chan_info rc = %x\n",ret);
+ break;
+ }
+ mtype = rData[1]; /* channel medium type */
+ if (mtype == 4) { /* 802.3 LAN type*/
+ if (fdebug) printf("chan[%d] = lan\n",j);
+ chn = (uchar)j;
+ break;
+ }
+ }
+ *chan = chn;
+ return(ret);
+}
+
+int SoftwareIdResponse(uchar *buf, int blen, uchar hnd, uchar chan)
+{
+ int rv = 0;
+ uchar resp[12] = {0,0xa6,0,0,0,1,0,0x00,0x01,0x57,0x00,0x01};
+#ifdef WIN32
+ /* check OS version & arch (32/64) */
+#else
+ struct utsname uts;
+ rv = uname(&uts);
+ // uts.release=`uname -r` uts.machine=x86_64,ia64,i586,i386
+ // kver <= 24 bytes, mach/arch <= 6 bytes
+#endif
+
+#ifdef USE_LANMSG
+ rv = SendTimedLanMessageResponse_Ex( (ImbPacket *)buf, (char *)(&resp), 12,
+ IMBPTIMEOUT, hnd, chan);
+#else
+ rv = SendTimedEmpMessageResponse_Ex((ImbPacket *)buf, (char *)(&resp), 12,
+ IMBPTIMEOUT, hnd,chan);
+#endif
+ if (fdebug) msgout("SoftwareIdResponse(%d) ret = %d\n",chan,rv);
+ return(rv);
+}
+
+
+int SmsOsResponse(uchar *buf, int blen, uchar func, uchar hnd, uchar chan)
+{
+ int rv = 0;
+ char cc = 0;
+ if (frunscript) {
+ write_syslog("igetevent -a running script\n");
+ rv = system(run_script);
+ if (fdebug) msgout("run(%s) ret = %d\n",run_script,rv);
+ }
+ switch(func) /*data byte has function*/
+ {
+ case 0x01: /*shutdown & power down*/
+ rv = SendTimedEmpMessageResponse_Ex((ImbPacket *)buf, &cc,1,
+ IMBPTIMEOUT, hnd,chan);
+ if (fdebug) msgout("OsResponse(%d) ret = %d\n",chan,rv);
+ if (!fAsyncNOP) {
+ write_syslog("igetevent -a initiating OS shutdown\n");
+ rv = system(SHUTDOWN_CMD);
+ if (fdebug) msgout("shutdown ret = %d\n",rv);
+ }
+ break;
+ case 0x02: /*shutdown & reset*/
+ rv = SendTimedEmpMessageResponse_Ex((ImbPacket *)buf, &cc,1,
+ IMBPTIMEOUT, hnd,chan);
+ if (fdebug) msgout("OsResponse(%d) ret = %d\n",chan,rv);
+ if (!fAsyncNOP) {
+ write_syslog("igetevent -a initiating OS reboot\n");
+ rv = system(REBOOT_CMD);
+ if (fdebug) msgout("reboot ret = %d\n",rv);
+ }
+ break;
+ default:
+ if (fdebug) msgout("igetevent -a unknown function %d\n",func);
+ rv = 1;
+ break;
+ }
+ return(rv);
+}
+
+/*
+ * get_imb_event
+ * This only gets certain IMB events, like
+ * OS requests (e.g. shutdown), and get_software_id
+ */
+static int get_imb_event(uchar etype, int timeout, uchar *evt)
+{
+ int ret = -1;
+ int i;
+ int done = 0;
+ ulong mlen;
+ uchar buffer[512];
+ uchar sendbuf[18];
+ static uint asyseqnum = 0;
+ uchar chan;
+ uchar sessHandle = 0;
+ uchar privilege = 0;
+ uchar cmd, func;
+ // uchar *pbuf;
+
+ ret = GetBmcLanChannel(&chan);
+
+ /* clean out pre-existing async messages */
+ while(1) {
+ mlen = sizeof(buffer);
+ if (GetAsyncImbpMessage((ImbPacket *)buffer,&mlen, IMBPTIMEOUT,
+ &asyseqnum, IPMB_CHANNEL) != 0)
+ break;
+ if (fdebug) msgout("cleaned out an IPMB message seq=%d\n",asyseqnum);
+ }
+ while(1) {
+ mlen = sizeof(buffer);
+ if (GetAsyncImbpMessage((ImbPacket *)buffer,&mlen, IMBPTIMEOUT,
+ &asyseqnum, LAN_CHANNEL) != 0)
+ break;
+ if (fdebug) msgout("cleaned out a LAN message seq=%d\n",asyseqnum);
+ }
+ ret = RegisterForImbAsyncMessageNotification(&imb_handle);
+ if (fdebug)
+ msgout("RegisterForImbAsync ret=%d, handle=%x\n",ret,imb_handle);
+ if (ret != 0) {
+ msgout("RegisterAsync error %d\n",ret);
+ return(ret);
+ }
+
+ for (i = 0; (timeout == 0) || (i < timeout); i++)
+ { /*get one imb event*/
+ if (fdebug) msgout("IsAsyncMessageAvailable ...\n");
+ if (IsAsyncMessageAvailable(imb_handle) == 0)
+ {
+ if (fdebug) msgout("Async Message is Available\n");
+ mlen = sizeof(buffer);
+ ret = GetAsyncImbpMessage_Ex ((ImbPacket *)buffer, &mlen,
+ IMBPTIMEOUT, &asyseqnum, ANY_CHANNEL,
+ &sessHandle, &privilege);
+ /* Hack: buffer contains an extra byte to return channel */
+ if (fdebug)
+ msgout("GetAsync(%d,%d) ret = %d, newchan=%x\n",
+ asyseqnum,chan,ret,buffer[mlen]);
+ if (ret == 0) {
+ /* get the async message command */
+ if (fdebug) dump_buf("async msg",buffer,mlen+1,0);
+ chan = buffer[mlen];
+ if (mlen > 16) mlen = 16;
+ if (buffer[0] == sms_sa) {
+ memcpy(&sendbuf[0],buffer,mlen);
+ } else { /* handle shorter format for some BMCs */
+ sendbuf[0] = sms_sa;
+ memcpy(&sendbuf[1],buffer,mlen);
+ }
+ cmd = sendbuf[5]; func = sendbuf[6];
+ msgout("got async msg: cmd=%02x len=%d\n",cmd,mlen);
+ memcpy(evt,sendbuf,mlen);
+
+ switch(cmd) {
+ case CMD_GET_SOFTWARE_ID: /*Get Software ID*/
+ ret = SoftwareIdResponse(sendbuf,mlen,sessHandle,chan);
+ break;
+ case CMD_SMS_OS_REQUEST: /*SMS OS Request*/
+ ret = SmsOsResponse(sendbuf,mlen,func,sessHandle,chan);
+ if (ret == 0) done = 1;
+ break;
+ default:
+ ret = LAN_ERR_INVPARAM;
+ msgout("SmsOS cmd %02x unknown, ret = %d\n",cmd,ret);
+ }
+ if (fdebug)
+ msgout("async msg cmd=%02x ret = %d\n",cmd,ret);
+ if (done == 1) {
+ if (func == 0x01) msgout("shutting down\n");
+ else msgout("rebooting\n");
+ ret = 0x81;
+ break;
+ }
+ }
+ } /*endif have an event*/
+ else ret = 0x80; /* no event yet */
+ } /*loop for one event*/
+ if (fdebug) msgout("Unregister for imb events\n");
+ UnRegisterForImbAsyncMessageNotification (imb_handle,0);
+ return(ret);
+}
+#endif
+ /*endif DO_ASYNC*/
+
+#ifdef DO_MVL
+/* Linux, enable MV OpenIPMI interface */
+extern int register_async_mv(uchar cmd, uchar netfn); /*see ipmimv.c*/
+extern int unregister_async_mv(uchar cmd, uchar netfn); /*see ipmimv.c*/
+extern int getevent_mv(uchar *evt_data, int *evt_len, uchar *cc, int t);
+extern int ipmi_rsp_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus,
+ uchar *pdata, int sdata, char fdebugcmd);
+
+static int send_mv_asy_resp(uchar *evt)
+{
+ uchar cmd, sa, bus, cc;
+ uchar data0[12] = {0,0xa6,0,0,0,1,0,0x00,0x01,0x57,0x00,0x01};
+ uchar data1[1] = { 0x00 };
+ uchar rdata[80];
+ int sdata, rlen, i;
+ uchar *pdata;
+ int rv = -1;
+
+ cmd = evt[2];
+ sa = sms_sa; /* sa = SMS_SA (0x81) */
+ bus = 0x01; /* usu lan_ch == 1 */
+ switch(cmd) {
+ case CMD_GET_SOFTWARE_ID: /*software id*/
+ pdata = &data0[0];
+ sdata = sizeof(data0);
+ break;
+ case CMD_SMS_OS_REQUEST: /*restart*/
+ pdata = &data1[0];
+ sdata = sizeof(data1);
+ break;
+ default: rv = LAN_ERR_INVPARAM; return (rv);
+ break;
+ }
+ rv = ipmi_rsp_mv(cmd, (NETFN_APP | 0x01), sa, bus, BMC_LUN,
+ pdata,sdata, fdebug);
+ if (rv == 0) {
+ for (i = 0; i < 5; i++)
+ {
+ rlen = sizeof(rdata);
+ rv = getevent_mv(rdata,&rlen,&cc,1);
+ if (fdebug) msgout("send_mv_asy_resp: rv=%d cc=%x\n",rv,cc);
+ if (rv == 0 && cc == 0) {
+ if (fdebug) msgout("got rsp ccode: type=%02x len=%d cc=%x\n",
+ rdata[0],rlen,rdata[3]);
+ if (rlen > 0) rv = rdata[3]; /*cc*/
+ break;
+ }
+ os_usleep(0,5000); /*wait 5 ms*/
+ }
+ }
+ return (rv);
+}
+
+static int get_mv_asy_event(uchar cmd, int timeout, uchar *evt)
+{
+ int ret = -1;
+ int rv = -1;
+ uchar cc = 0;
+ uchar rdata[120];
+ int rlen, i;
+
+ rv = register_async_mv(cmd,NETFN_APP); /*reserved,GetSoftwareID*/
+ if (rv != 0) return(rv);
+
+ for (i = 0; (timeout == 0) || (i < timeout); i++)
+ { /*get one async event*/
+ rv = getevent_mv(rdata,&rlen,&cc,timeout);
+ if (fdebug)
+ msgout("get_mv_asy_event: i=%d cmd=%x rv=%d cc=%x\n",i,cmd,rv,cc);
+ if (rv == 0 && cc == 0) {
+ msgout("got async msg: type=%02x cmd=%x len=%d\n",
+ rdata[0],rdata[2],rlen);
+ if (fdebug) dump_buf("async msg",rdata,rlen,0);
+ /* check recv_type == 3 (IPMI_CMD_RECV_TYPE) */
+ if (rdata[0] == 3 && rdata[2] == cmd) {
+ if (rlen > 16) rlen = 16;
+ memcpy(evt,rdata,rlen);
+ break;
+ } else { /*else msg, but no match*/
+ rv = ERR_BAD_PARAM;
+ break;
+ }
+ }
+ else do_wait(wait_interval); /*wait 1 sec*/
+ }
+ ret = unregister_async_mv(cmd,NETFN_APP); /*reserved,GetSoftwareID*/
+ return(rv);
+}
+#endif
+
+static int get_evt_method(char *evtmethod)
+{
+ int method = METHOD_UNKNOWN;
+ if (fAsync) {
+ if (drvtype == DRV_MV) method = METHOD_ASYNC_MV;
+ else /* if (drvtype == DRV_IMB) */ method = METHOD_ASYNC_IMB;
+ } else if (fselevts) method = METHOD_SEL_EVTS;
+ else { /*fmsgevts*/
+ if (drvtype == DRV_MV) method = METHOD_MSG_MV;
+ else method = METHOD_MSG_GET;
+ }
+ if (evtmethod != NULL)
+ strcpy(evtmethod,methodstr[method]);
+ return(method);
+}
+
+static int get_sel_entry(ushort recid, ushort *nextid, uchar *rec)
+{
+ uchar ibuf[6];
+ uchar rbuf[32];
+ int rlen;
+ ushort xid, id = 0;
+ uchar cc;
+ int rv;
+
+ ibuf[0] = 0;
+ ibuf[1] = 0;
+ ibuf[2] = (recid & 0x00ff);
+ ibuf[3] = (recid & 0xff00) >> 8;
+ ibuf[4] = 0;
+ ibuf[5] = 0xFF; /*get entire record*/
+ rlen = sizeof(rbuf);
+ rv = ipmi_cmd(GET_SEL_ENTRY, ibuf, 6, rbuf, &rlen, &cc, fdebug);
+ if (rv == 0) {
+ if (cc != 0) rv = cc;
+ else { /*success*/
+ xid = rbuf[0] + (rbuf[1] << 8); /*next rec id*/
+ memcpy(rec,&rbuf[2],16);
+ *nextid = xid;
+ id = rbuf[2] + (rbuf[3] << 8); /*curr rec id*/
+ /* recid (requested) should match newid (received) */
+ if (fdebug) {
+ if ((recid != id) && (recid != LAST_REC) && (recid != 0)) {
+ /* the OpenIPMI driver does this sometimes */
+ msgout("get_sel MISMATCH: recid=%x newid=%x next=%x\n",
+ recid,id,xid);
+ dump_buf("get_sel cmd",ibuf,6,0);
+ dump_buf("get_sel rsp",rbuf,rlen,0);
+ }
+ }
+ }
+ }
+ if (fdebug) msgout("get_sel(%x) rv=%d cc=%x id=%x next=%x\n",
+ recid,rv,cc,id,*nextid);
+ return(rv);
+}
+
+static int startevent_sel(ushort *precid, uint *ptime)
+{
+ FILE *fd;
+ uchar rec[24];
+ uint t = 0;
+ ushort r = 0;
+ ushort r2 = 0;
+ int rv = -1;
+
+ fd = fopen(idxfile,"r");
+ if (fd == NULL) fd = fopen(idxfile2,"r"); /*handle old location*/
+ if (fdebug) msgout("start: idxfile=%s fd=%p\n",idxfile,fd);
+ if (fd != NULL) {
+ // Read the file, get savtime & savid
+ rv = fscanf(fd,"%x %x",&t,&r);
+ fclose(fd);
+ if (r == LAST_REC) r = 0;
+ rv = 0; /*read it, success*/
+ } else { /* treat as first time */
+ r = LAST_REC;
+ rv = get_sel_entry(r,&r2,rec);
+ if (rv == 0) {
+ memcpy(&t,&rec[3],4);
+ r = rec[0] + (rec[1] << 8); /*use current rec id*/
+ } else r = 0;
+ rv = 1; /*first time*/
+ }
+ if (fdebug) msgout("start: recid=%x time=%x\n",r,t);
+ *ptime = t;
+ *precid = r;
+ return(rv);
+}
+
+static int syncevent_sel(ushort recid, uint itime)
+{
+ FILE *fd;
+ int rv;
+ // Rewrite the saved time & record id
+ if (fdebug) msgout("sync: recid=%x time=%x\n",recid,itime);
+ fd = fopen(idxfile,"w");
+ if (fd == NULL) {
+ msgout("syncevent: cannot open %s for writing\n",idxfile);
+ rv = -1;
+ } else {
+ fprintf(fd,"%x %x\n",itime,recid);
+ fclose(fd);
+ rv = 0;
+ }
+ return(rv);
+}
+
+int getevent_sel(uchar *rdata, int *rlen, uchar *ccode)
+{
+ uchar rec[24];
+ int rv = 0;
+ ushort newid;
+ ushort nextid;
+ ushort recid;
+
+ /* get current last record */
+ recid = sel_recid;
+ rv = get_sel_entry(recid,&nextid,rec);
+ if (rv == 0xCB && recid == 0) { /* SEL is empty */
+ *ccode = (uchar)rv; /* save the real ccode */
+ rv = 0x80; /* this is ok, just keep waiting */
+ }
+ if (rv == 0) {
+ if (fdebug) msgout("sel ok, id=%x next=%x\n",recid,nextid);
+ if ((nextid == LAST_REC) || (recid == nextid)) {
+ *ccode = 0x80; /*nothing new*/
+ } else {
+ recid = nextid; /* else get new one */
+ rv = get_sel_entry(recid,&nextid,rec);
+ if (rv == 0) { /* new event */
+ newid = rec[0] + (rec[1] << 8);
+ if (drvtype == DRV_MV && recid != newid) {
+ /* handle MV driver bug, try to get next one. */
+ if (fdebug) msgout("%s bug, record mismatch\n",
+ show_driver_type(DRV_MV));
+ }
+ if (fdebug) msgout("recid=%x newid=%x next=%x\n",
+ recid,newid,nextid);
+ memcpy(rdata,rec,16);
+ *rlen = 16;
+ *ccode = 0;
+ sel_recid = recid; /*or newid*/
+ memcpy(&sel_time,&rec[3],4);
+ }
+ }
+ }
+ else { /* Error reading last recid saved */
+ if (fdebug) msgout("sel recid %x error, rv = %d\n",recid,rv);
+ /* We want to set sel_recid = 0 here for some errors. */
+ if (rv == 0xCB || rv == 0xCD) { /* empty, or wrong SDR id */
+ sel_recid = 0;
+ *ccode = (uchar)rv;
+ rv = 0x80; /* wait again */
+ }
+ }
+ return(rv);
+}
+
+static int get_event(uchar etype, uchar snum, int timeout,
+ uchar *evt, uchar *stype)
+{
+ int ret = 0;
+ uchar rdata[64];
+ int rlen;
+ uchar ccode;
+ int fretry;
+ int i;
+
+ for (i = 0; (timeout == 0) || (i < timeout); i++)
+ {
+ rlen = sizeof(rdata);
+ fretry = 0; ccode = 0;
+ if (fselevts) {
+ ret = getevent_sel(rdata,&rlen,&ccode);
+ } else
+#ifdef DO_MVL
+ if (drvtype == DRV_MV) { /* if MV OpenIPMI driver (Linux only) */
+ if (timeout == 0) wait_interval = 0;
+ /* use special MV API instead (see ipmimv.c) */
+ ret = getevent_mv(rdata,&rlen,&ccode,timeout);
+ } else
+#endif
+ ret = ipmi_cmd(READ_EVENT_MSGBUF,NULL,0,rdata,&rlen,&ccode,fdebug);
+ /* now we have an event from one of the above methods*/
+
+ /* IPMI 1.5 spec, section 18.8 says cc 0x80 means
+ * "data not available (queue/buffer empty)" */
+ if (ret == 0 && ccode != 0) { ret = ccode; }
+ if (ret == 0x80) {
+ fretry = 1;
+ do_wait(wait_interval); /*wait 1 sec*/
+ } else {
+ if (ret == 0) {
+ char ismatch = 0;
+ /* parse event types for a specified type */
+ /* etype param == 0xff means get any event */
+ /* rdata[10] is sensor_type, rdata[11] is sensor_num */
+ if ((etype == 0xff) || (etype == rdata[10])) ismatch++;
+ if ((snum == 0xff) || (snum == rdata[11])) ismatch++;
+ if (ismatch == 2) {
+ /*event sensor type matches*/
+ memcpy(evt,rdata,rlen);
+ *stype = rdata[10]; /* return sensor type */
+ } else { /* keep looking */
+ do_wait(wait_interval);
+ continue;
+ }
+ }
+ /* if here, either got one, or need to return error */
+ break;
+ }
+ } /*end for loop*/
+ return(ret);
+}
+
+int send_nmi(void)
+{
+ uchar idata[8];
+ uchar rdata[30];
+ int rlen;
+ uchar ccode;
+ int ret;
+
+ idata[0] = 4; /* do NMI */
+ rlen = sizeof(rdata);
+ ret = ipmi_cmdraw( CHASSIS_CTL, NETFN_CHAS, BMC_SA,PUBLIC_BUS,BMC_LUN,
+ idata,1, rdata,&rlen,&ccode, fdebug);
+ if (ret == 0 && ccode != 0) ret = ccode;
+ return(ret);
+}
+
+void show_event(uchar *evt,char *obuf, int sz)
+{
+ int i;
+ char sysbuf[250];
+ /* obuf should be 132 chars or more */
+
+ msgout("event data: ");
+ for (i=0; i<16; i++) msgout("%02x ",evt[i]);
+ msgout("\n");
+
+ decode_sel_entry(evt,obuf,sz);
+ msgout(obuf); /*writes to outfile*/
+ /* write the message to syslog also. */
+ snprintf(sysbuf,sizeof(sysbuf),"%s: %s",progname,obuf);
+ write_syslog(sysbuf);
+}
+
+static void ievt_cleanup(void)
+{
+ char obuf[48];
+ if (fselevts) syncevent_sel(sel_recid,sel_time);
+ snprintf(obuf,sizeof(obuf),"%s exiting.\n",progname);
+ msgout(obuf);
+ write_syslog(obuf);
+ free_sdr_cache(sdrs);
+ iclose();
+ exit(EXIT_SUCCESS);
+}
+
+#if defined(WIN32) | defined(DOS)
+/* no daemon code */
+static void ievt_siginit(void) { return; }
+#else
+/* Linux daemon code */
+#include <signal.h>
+static void ievt_sighnd(int sig)
+{
+ ievt_cleanup();
+ exit(EXIT_SUCCESS);
+}
+
+static void ievt_siginit(void);
+static void ievt_siginit(void)
+{
+ struct sigaction sact;
+
+ /* handle signals for cleanup */
+ sact.sa_handler = ievt_sighnd;
+ sact.sa_flags = 0;
+ sigemptyset(&sact.sa_mask);
+ sigaction(SIGINT, &sact, NULL);
+ sigaction(SIGQUIT, &sact, NULL);
+ sigaction(SIGTERM, &sact, NULL);
+}
+
+static int mkdaemon(int fchdir, int fclose);
+static int mkdaemon(int fchdir, int fclose)
+{
+ int fdlimit = sysconf(_SC_OPEN_MAX); /*fdlimit usu = 1024.*/
+ int fd = 0;
+
+
+ fdlimit = fileno(stderr); /*only close files up to stderr*/
+ switch (fork()) {
+ case 0: break;
+ case -1: return -1;
+ default: _exit(0); /* exit the original process */
+ }
+ if (setsid() < 0) return -1; /* shouldn't fail */
+ switch (fork()) {
+ case 0: break;
+ case -1: return -1;
+ default: _exit(0); /* exit the original process */
+ }
+ if (fchdir) {
+ chdir("/");
+ /* umask(0022); * leave file creation mask at default (0022) & 0777 */
+ }
+ if (fclose) {
+ /* Close stdin,stdout,stderr and replace them with /dev/null */
+ for (fd = 0; fd < fdlimit; fd++) close(fd);
+ open("/dev/null",O_RDWR);
+ dup(0); dup(0);
+ }
+ return 0;
+}
+#endif
+
+static void iclose()
+{
+ /* close out any IPMI handles or sessions */
+#ifdef THREADS_OK
+#ifdef WIN32
+ if (threadid != NULL) CloseHandle(threadid);
+#else
+ /* thread close not needed in Linux */
+#endif
+#endif
+ ipmi_close_();
+ if (fbackground && fdout != NULL) fclose(fdout);
+}
+
+#ifdef METACOMMAND
+int i_getevt(int argc, char **argv)
+#else
+#ifdef WIN32
+int __cdecl
+#else
+int
+#endif
+main(int argc, char **argv)
+#endif
+{
+ int ret = 0;
+ int c, j;
+ uchar devrec[16];
+ uchar event[16];
+ uchar sa, lun;
+ uchar enables = 0;
+ uchar fevmsgok = 0;
+ uchar sensor_type = 0;
+ uchar msg_flags = 0;
+ FILE *fp;
+ char outbuf[160];
+ char tmpout[20];
+ char *sdesc;
+
+ fdout = stdout;
+ msgout("%s ver %s\n", progname,progver);
+
+ while ( (c = getopt(argc,argv,"abce:lmn:or:st:uvT:V:J:YEF:P:N:R:U:Z:x?")) != EOF )
+ switch(c) {
+ case 'a': fAsync = 1; /* imb async message method */
+ /* chenge the output log filename */
+ sdesc = strstr(outfile,"evt.log");
+ if (sdesc != NULL) strcpy(sdesc,"asy.log");
+ break;
+ case 'b': fbackground = 1; break; /* background */
+ case 'c': fcanonical = 1; break; /* canonical */
+ case 'e': /* event sensor type */
+ if (strncmp(optarg,"0x",2) == 0)
+ evt_stype = htoi(&optarg[2]);
+ else evt_stype = atob(optarg);
+ break;
+ case 'l': fAsyncNOP = 1; break; /* do not reset (for testing)*/
+ case 'm': fmsgevts = 1; break; /* use local getmessage method */
+ case 'n': /* event sensor num, always hex */
+ if (strncmp(optarg,"0x",2) == 0)
+ evt_snum = htoi(&optarg[2]);
+ else evt_snum = htoi(&optarg[0]);
+ break;
+ case 'o': frunonce = 1; break; /* only run once for first event */
+ case 'r': /* run script (or binary) on an event */
+ run_script = optarg;
+ fp = fopen(run_script,"r");
+ if (fp == NULL) {
+ printf("cannot open %s\n",run_script);
+ ret = ERR_FILE_OPEN;
+ goto do_exit;
+ } else {
+ fclose(fp);
+ frunscript = 1;
+ }
+ break;
+ case 's': fselevts = 1; break; /* use SEL event method*/
+ case 't': timeout = atoi(optarg); fsettime = 1; break; /*timeout*/
+ case 'u': futc = 1; break;
+ case 'x': fdebug = 1; break; /* debug messages */
+ case 'v': fdebug = 3; break; /* verbose debug with lan */
+ case 'N': /* nodename */
+ case 'U': /* remote username */
+ case 'P': /* remote password */
+ case 'R': /* remote password */
+ case 'E': /* get password from IPMI_PASSWORD environment var */
+ case 'F': /* force driver type */
+ case 'T': /* auth type */
+ case 'J': /* cipher suite */
+ case 'V': /* priv level */
+ case 'Y': /* prompt for remote password */
+ case 'Z': /* set local MC address */
+ parse_lan_options(c,optarg,fdebug);
+ break;
+ default:
+ printf("Usage: %s [-abenorsux -t sec -NPRUEFTVY]\n", progname);
+ printf(" where -a use Async method\n");
+ printf(" -b run in Background\n");
+ printf(" -c use Canonical/delimited event format\n");
+ printf(" -e T wait for specific event sensor type T\n");
+ printf(" -n N wait for specific event sensor num N\n");
+ printf(" -o run Once for the first event\n");
+ printf(" -r F Run file F when an event occurs\n");
+ printf(" -s use SEL event method\n");
+ printf(" -t N set timeout to N seconds\n");
+ printf(" -u use raw UTC time\n");
+ printf(" -x show eXtra debug messages\n");
+ print_lan_opt_usage();
+ ret = ERR_USAGE;
+ goto do_exit;
+ }
+
+ fipmilan = is_remote();
+ ret = ipmi_getdeviceid(devrec,16,fdebug);
+ if (ret != 0) {
+ goto do_exit;
+ } else {
+ ipmi_maj = devrec[4] & 0x0f;
+ ipmi_min = devrec[4] >> 4;
+ show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min);
+ vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16);
+ prod_id = devrec[9] + (devrec[10] << 8);
+ if (vend_id == VENDOR_INTEL) {
+ if (prod_id == 0x003E) /* NSN2U or CG2100 Urbanna */
+ sms_sa = 0x41;
+ }
+ }
+
+ /* get event receiver */
+ ret = get_event_receiver(&sa ,&lun);
+ if (ret != 0)
+ msgout("event receiver error %d\n",ret);
+ else msgout("event receiver sa = %02x lun = %02x\n",sa,lun);
+
+ ret = get_bmc_enables(&enables);
+ if (ret != 0) msgout("bmc enables error %d\n",ret);
+ else {
+ msgout("bmc enables = %02x\n",enables);
+ if ((enables & 0x02) == 2) fevmsgok = 1;
+ else fevmsgok = 0;
+ }
+ if (fevmsgok == 0 && !fipmilan) {
+ msgout("Event Message Buffers not enabled.\n");
+ enables |= 0x0f; /* 0x08=SEL, 0x02=EvtMsgBuf, rest is gravy */
+ ret = set_bmc_enables(enables);
+ if (ret != 0) {
+ msgout("set_bmc_enables error 0x%x\n",ret);
+ }
+ else msgout("set_bmc_enables success\n");
+ }
+ if (fipmilan && !fselevts) {
+ msgout("Only the SEL method (-s) is supported over IPMI LAN\n");
+ ret = LAN_ERR_NOTSUPPORT;
+ goto do_exit;
+ }
+ ret = get_msg_flags(&msg_flags);
+ msgout("igetevent reading sensors ...\n");
+ write_syslog("igetevent reading sensors ...\n");
+ ret = get_sdr_cache(&sdrs);
+ // if (!fipmilan) set_sel_opts(1,0, NULL,fdebug);
+ if (fdebug) msgout("get_sdr_cache ret = %d\n",ret);
+ if (ret == 0) set_sel_opts(1, fcanonical, sdrs,fdebug,futc);
+ else ret = 0; /*if error, keep going anyway*/
+
+ if (fselevts) {
+#ifdef WIN32
+ { /*resolve path of idxfile*/
+ char *ipath;
+ ipath = getenv("ipmiutildir"); /*ipmiutil directory path*/
+ if (ipath != NULL) {
+ if (strlen(ipath)+12 < sizeof(idxfile)) {
+ sprintf(idxfile,"%s\\%s",ipath,"\\",IDXFILE);
+ }
+ }
+ }
+#endif
+
+ if (fipmilan) {
+ char *node;
+ node = get_nodename();
+ strcat(idxfile,"-");
+ strcat(idxfile,node);
+ strcat(idxfile2,"-");
+ strcat(idxfile2,node);
+ strcat(outfile,"-");
+ strcat(outfile,node);
+ }
+ ret = startevent_sel(&sel_recid,&sel_time);
+ ret = 0; /*ignore any earlier errors, keep going*/
+ }
+
+ drvtype = get_driver_type();
+ if (fdebug) msgout("driver_type = %d (%s)\n",
+ drvtype,show_driver_type(drvtype));
+
+ if (evt_stype == 0xFF) sdesc = "any event";
+ else sdesc = get_sensor_type_desc(evt_stype);
+ if (evt_snum == 0xFF) tmpout[0] = 0;
+ else sprintf(tmpout,"with snum %02x",evt_snum);
+ if (evt_stype != 0xFF || evt_snum != 0xFF)
+ msgout("Look for event sensor type %02x (%s) %s\n", evt_stype,sdesc,tmpout);
+
+#ifdef TEST_SEL
+ /* This is used to verify that the interface returns valid next ids,
+ * and that the get_sel_entry is ok. */
+ {
+ int i;
+ ushort r, r1, r2;
+ uchar rec[40];
+ int rv;
+ r = 0;
+ for (i = 0; i < 4; i++)
+ {
+ rv = get_sel_entry(r,&r2,rec);
+ if (rv == 0) {
+ r1 = rec[0] + (rec[1] << 8); /*get current rec id*/
+ if (fdebug) msgout("get_sel: r=%x r1=%x rnext=%x\n",r,r1,r2);
+ show_event(&rec[0],outbuf,sizeof(outbuf));
+ r = r2;
+ } else break;
+ }
+ }
+#endif
+ if (drvtype == DRV_IMB) fAsyncOK = 1;
+ else if (drvtype == DRV_MV) {
+ if (fsettime == 0) timeout = 0; /*DRV_MV default to infinite*/
+ fAsyncOK = 1;
+ } else fAsyncOK = 0;
+
+ if (fAsync && (!fAsyncOK)) {
+ msgout("Cannot open %s or %s driver, required for -a\n",
+ show_driver_type(DRV_IMB),show_driver_type(DRV_MV));
+ ret = ERR_NO_DRV;
+ goto do_exit;
+ }
+
+ if (fbackground) { /* convert to a daemon if background */
+#ifdef WIN32
+ msgout("Background not implemented for Windows\n");
+ ret = LAN_ERR_NOTSUPPORT;
+ goto do_exit;
+#elif defined(DOS)
+ msgout("Background not implemented for DOS\n");
+ ret = LAN_ERR_NOTSUPPORT;
+ goto do_exit;
+#else
+ /* make sure we can open the log file before doing mkdaemon */
+ fdout = fopen(outfile,"a");
+ if (fdout == NULL)
+ printf("%s: Cannot open %s\n", progname,outfile);
+ else {
+ pid_t p;
+ fclose(fdout);
+
+ ret = mkdaemon(1,1);
+ if (ret != 0) {
+ msgout("%s: Cannot become daemon, ret = %d\n", progname,ret);
+ goto do_exit;
+ }
+ /* open a log file for messages, set fdout */
+ fdout = fopen(outfile,"a");
+#ifdef METACOMMAND
+ /* make sure driver debug also goes to log */
+ fpdbg = fdout;
+ fperr = fdout;
+#endif
+ p = getpid();
+ msgout("PID %d: %s ver %s\n",p,progname,progver); /*log start message*/
+ }
+#endif
+ }
+ ievt_siginit();
+
+ if (fAsync && (fAsyncOK)) /*use imb/mv async messages*/
+ {
+ msgout("Wait for an async event\n"); /* no timeout */
+ if (drvtype == DRV_IMB)
+ {
+#ifdef DO_ASYNC
+#ifdef THREADS_OK
+#ifdef WIN32
+ /* Windows threads */
+ threadid = CreateThread(NULL, 0, &pollThread, NULL, 0, NULL);
+ if (threadid == NULL) pollThread(NULL);
+#else
+ /* Linux threads */
+ ret = pthread_create( &threadid, NULL, pollThread, (void*) message);
+ // if (ret == 0) pthread_join( threadid, NULL);
+ // if (ret == 0) pthread_detach( threadid);
+#endif
+ if (fdebug) msgout("pollThread create ret=%d handle=%x\n",ret,threadid);
+#else
+ /* no threads */
+ pollThread(NULL);
+#endif
+ while (ret == 0)
+ { /*wait for imb message events*/
+ msgout("Waiting %d seconds for an async event ...\n",timeout);
+ ret = get_imb_event(0xff,timeout,event);
+ if (ret == 0x81) { /*ok, shutting down OS*/
+ ret = 0;
+ break;
+ }
+ if (frunonce) break;
+ if (timeout == 0 && ret == 0x80) { /*0x80 = no data yet */
+ if (fdebug) msgout("get_event timeout, no event yet.\n");
+ do_wait(wait_interval);
+ ret = 0; /*ok, keep going*/
+ }
+ }
+#endif
+ } /*endif DRV_IMB*/
+#ifdef DO_MVL
+ else { /*DRV_MV*/
+ int stage;
+ stage = 0;
+ while (stage < 3)
+ { /*wait for mv message events*/
+ if (fdebug) msgout("Waiting for async_mv event, stage %d\n",stage);
+ if (stage == 0) {
+ ret = get_mv_asy_event(CMD_GET_SOFTWARE_ID,timeout,event);
+ if (fdebug) msgout("got SmsOS GetSWID event ret = %d\n",ret);
+ /* send a reply */
+ if (ret == 0) ret = send_mv_asy_resp(event);
+ if (ret == 0) stage = 1; /* got the SoftwareID request/response */
+ else stage = 0;
+ }
+ if (stage == 1) {
+ /* get the reset command */
+ memset(event,0,sizeof(event));
+ ret = get_mv_asy_event(CMD_SMS_OS_REQUEST,timeout,event);
+ if (fdebug) msgout("got SmsOS GetSmsOS event ret = %d\n",ret);
+ if (ret == 0) ret = send_mv_asy_resp(event);
+ if (ret == 0) stage = 2;
+ else stage = 0;
+ }
+ if (stage == 2) { /* got the SmsOs request in event */
+ uchar cmd, func;
+ cmd = event[2];
+ func = event[3];
+ if (cmd != CMD_SMS_OS_REQUEST) { /*cmd*/
+ ret = LAN_ERR_INVPARAM;
+ if (fdebug) msgout("SmsOS cmd %x ret = %d\n",cmd,ret);
+ } else {
+ if (frunscript) {
+ write_syslog("igetevent -a running script\n");
+ ret = system(run_script);
+ if (fdebug) msgout("run(%s) ret = %d\n",run_script,ret);
+ }
+ if (!fAsyncNOP)
+ switch(func) { /*subfunction*/
+ case 0x01: /*shutdown & power down*/
+ write_syslog("igetevent -a OS shutdown\n");
+ ret = system(SHUTDOWN_CMD);
+ msgout("SmsOs shutdown, ret = %d\n",ret);
+ break;
+ case 0x02: /*shutdown & reboot*/
+ write_syslog("igetevent -a OS reboot\n");
+ ret = system(REBOOT_CMD);
+ msgout("SmsOs reboot, ret = %d\n",ret);
+ break;
+ case 0x03: /*send NMI locally*/
+ write_syslog("igetevent -a NMI\n");
+ ret = send_nmi();
+ msgout("SmsOs NMI, ret = %d\n",ret);
+ default:
+ ret = LAN_ERR_INVPARAM;
+ msgout("SmsOS func %02x, ret = %d\n",func,ret);
+ break;
+ }
+ }
+ if (ret == 0) stage = 3; /*done, exit loop*/
+ else {
+ if (fdebug) msgout("SmsOS error = %d, start over\n",ret);
+ stage = 0; /*start over*/
+ }
+ } /*endif stage 2*/
+ } /*end-while*/
+ } /*end else DRV_MV*/
+#endif
+
+ } else { /*not Async, std IPMI events */
+ if (fselevts) {
+ msgout("Get IPMI SEL events after ID %04x\n",sel_recid);
+ } else
+ msgout("Get IPMI events from %s driver\n",show_driver_type(drvtype));
+ j = get_evt_method(tmpout);
+ sprintf(outbuf,"igetevent waiting for events via method %d (%s)\n",
+ j, tmpout);
+ msgout(outbuf);
+ write_syslog(outbuf);
+
+ /* loop on events here, like a daemon would. */
+ while (ret == 0)
+ { /*wait for bmc message events*/
+ msgout("Waiting %d seconds for an event ...\n",timeout);
+ /* note: could also get message flags here */
+ ret = get_event(evt_stype,evt_snum,timeout,event,&sensor_type);
+ if (fdebug) msgout("get_event ret = %d\n",ret);
+ if (ret == 0) { /* got an event successfully */
+ msgout("got event id %04x, sensor_type = %02x\n",
+ sel_recid, sensor_type);
+ show_event(event,outbuf,sizeof(outbuf));
+ if (fselevts) syncevent_sel(sel_recid,sel_time);
+ if (frunscript) { /*run some script for each event*/
+ char run_cmd[256];
+ sprintf(run_cmd,"%s \"%s\"\n",run_script,outbuf);
+ j = system(run_cmd);
+ msgout("run(%s $1), ret = %d\n",run_script,j);
+ ret = j; /*if that failed, exit loop*/
+ }
+ } else {
+ if (ret == 0x80) msgout("get_event timeout\n");
+ else msgout("get_event error: ret = 0x%x\n",ret);
+ }
+ if (frunonce) break;
+ if (timeout == 0 && ret == 0x80) { /*0x80 = no data yet */
+ if (fdebug) msgout("get_event timeout, no data yet.\n");
+ do_wait(wait_interval);
+ ret = 0; /*ok, keep going*/
+ }
+ } /*end while loop*/
+ }
+
+do_exit:
+ ievt_cleanup();
+ if (ret == 0x80) ret = 0;
+ // show_outcome(progname,ret); /*inert if background*/
+ return(ret);
+} /* end main()*/
+
+/* end getevent.c */