diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-06 18:04:32 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-06 18:04:32 +0200 |
commit | a7f89980e5b3f4b9a74c70dbc5ffe8aabd28be28 (patch) | |
tree | 41c4deec1fdfbafd7821b4ca7a9772ac0abd92f5 /util/ipmi_sample_evt.c |
Imported Upstream version 2.9.3upstream/2.9.3
Diffstat (limited to 'util/ipmi_sample_evt.c')
-rw-r--r-- | util/ipmi_sample_evt.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/util/ipmi_sample_evt.c b/util/ipmi_sample_evt.c new file mode 100644 index 0000000..b51ba24 --- /dev/null +++ b/util/ipmi_sample_evt.c @@ -0,0 +1,445 @@ +/* + * ipmi_sample_evt.c + * + * A sample IPMI utility to get IPMI SEL events. + * + * 09/10/12 Andy Cress - created + */ +/*M* +Copyright (c) 2012, Kontron America, 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: + + 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 America, Inc. 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 <stdarg.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> +#endif +#endif +#include <string.h> +#include "ipmicmd.h" + +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 dbg, char u); +extern char *get_sensor_type_desc(uchar stype); /*see ievents.c*/ +extern int get_sdr_cache(uchar **pret); /*see isensor.c*/ +extern void free_sdr_cache(uchar *pret); /*see isensor.c*/ +extern int write_syslog(char *msg); /*see isel.c*/ + +/* + * Global variables + */ +static char * progname = "ipmi_sample_evt"; +static char * progver = "1.0"; +static char fdebug = 0; +static char fset_mc = 0; +static char fipmilan = 0; +static char finit_ok = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static char *mytag = NULL; +static char *sdrfile = NULL; +static ushort sel_recid = 0; +static uint sel_time = 0; +static int wait_interval = 3; /* 3 seconds between calls */ +static uchar *sdrs = NULL; +static int drvtype = 0; /* driver_type from ipmicmd.h: 3=MV_OpenIPMI */ +FILE *fdout = NULL; +#define LAST_REC 0xFFFF +#ifdef WIN32 +static char idxfile[80] = "c:\\ipmievt.idx"; +static char outfile[80] = "c:\\ipmievt.log"; +#else +static char idxfile[80] = "/var/lib/ipmiutil/ipmievt.idx"; +static char outfile[80] = "/var/log/ipmievt.log"; +#endif + +/* These routines were copied from igetevent.c + * msgout, getevent_sel, syncevent_sel, show_event, ievt_cleanup + */ +static void ievt_cleanup(void); +static void msgout(char *pattn, ...) +{ + va_list arglist; + + if (fdout == NULL) return; + va_start( arglist, pattn ); + vfprintf( fdout, pattn, arglist ); + va_end( arglist ); + fflush( fdout ); +} + +#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); +} +#endif + +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 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[2],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 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 (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[2],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); +} + +static void ievt_cleanup(void) +{ + char obuf[48]; + snprintf(obuf,sizeof(obuf),"%s exiting.\n",progname); + msgout(obuf); + write_syslog(obuf); + if (finit_ok) { + syncevent_sel(sel_recid,sel_time); + free_sdr_cache(sdrs); + } + ipmi_close_(); /*inert if not opened*/ + exit(EXIT_SUCCESS); +} + +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); +} + +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +{ + int ret = 0; + char c; + uchar devrec[16]; + uchar event[32]; /*usu 16 bytes */ + char outbuf[160]; + char *s1; + int rlen; + uchar ccode; + uchar sensor_type; + + fdout = stderr; + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:s:t:xEF:N:P:R:T:U:V:YZ:?")) != EOF ) + switch(c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 's': sdrfile = optarg; break; + case 't': mytag = optarg; break; /* specific sensor tag */ + case 'x': fdebug = 1; break; /* debug messages */ + 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 '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 [-msx -NUPREFTVY]\n", progname); + printf(" where -x show eXtra debug messages\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -s File loads SDRs from File\n"); + printf(" -t tag search for 'tag' in SDRs\n"); + print_lan_opt_usage(); + exit(1); + } + /* Rather than parse_lan_options above, the set_lan_options function + * could be used if the program already knows the nodename, etc. */ + + fipmilan = is_remote(); + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + printf("Cannot do ipmi_getdeviceid, ret = %d\n",ret); + goto do_exit; + } else { /*success*/ + uchar ipmi_maj, ipmi_min; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + } + drvtype = get_driver_type(); + + /* could make it a daemon here, if desired */ + fdout = fopen(outfile,"a"); + if (fdout == NULL) { + printf("%s: Cannot open %s\n", progname,outfile); + fdout = stderr; + } else { + sprintf(outbuf,"%s ver %s started\n", progname,progver); + msgout(outbuf); + } + sprintf(outbuf,"%s reading sensors ...\n",progname); + write_syslog(outbuf); + ret = get_sdr_cache(&sdrs); + if (fdebug) msgout("get_sdr_cache ret = %d\n",ret); + if (ret == 0) set_sel_opts(1,0, sdrs,fdebug,0); + + if (fipmilan) { + char *node; + node = get_nodename(); + strcat(idxfile,"-"); + strcat(idxfile,node); + strcat(outfile,"-"); + strcat(outfile,node); + } + ret = startevent_sel(&sel_recid,&sel_time); + + ievt_siginit(); + finit_ok = 1; + ret = 0; /*ignore any earlier errors, keep going*/ + + while (ret == 0) + { /*wait for bmc message events*/ + if (fdebug) + msgout("%s: Polling every %d sec for a new event after id %x...\n", + progname, wait_interval, sel_recid); + rlen = sizeof(event); + ret = getevent_sel(event,&rlen,&ccode); + if (ret == 0) ret = ccode; + if (fdebug) msgout("getevent_sel ret = %d\n",ret); + if (ret == 0) { /* got an event successfully */ + sensor_type = event[10]; + msgout("got event id %04x, sensor_type = %02x\n", + sel_recid,sensor_type); + show_event(event,outbuf,sizeof(outbuf)); + syncevent_sel(sel_recid,sel_time); + } else if (ret == 0x80) { + ret = 0; /*keep waiting*/ + } else { + msgout("get_event error: ret = 0x%x\n",ret); + break; + } + os_usleep(wait_interval,0); + } /*end while loop*/ + +do_exit: + ievt_cleanup(); + show_outcome(progname,ret); + exit (ret); +} /* end main()*/ + +/* end ipmi_sample_evt.c */ |