1 /* 2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * Redistribution of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * Redistribution in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * Neither the name of Sun Microsystems, Inc. or the names of 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * This software is provided "AS IS," without a warranty of any kind. 20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 23 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 26 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 30 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 31 */ 32 #define _XOPEN_SOURCE 700 33 34 #include <stdio.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <sys/ioctl.h> 38 #include <errno.h> 39 #include <stdlib.h> 40 #include <inttypes.h> 41 #include <string.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <signal.h> 45 46 #if defined(HAVE_CONFIG_H) 47 # include <config.h> 48 #endif 49 50 #if defined(HAVE_SYS_IOCCOM_H) 51 # include <sys/ioccom.h> 52 #endif 53 54 #ifdef HAVE_PATHS_H 55 # include <paths.h> 56 #endif 57 58 #ifndef _PATH_VARRUN 59 # define _PATH_VARRUN "/var/run/" 60 #endif 61 62 #ifdef IPMI_INTF_OPEN 63 # if defined(HAVE_OPENIPMI_H) 64 # if defined(HAVE_LINUX_COMPILER_H) 65 # include <linux/compiler.h> 66 # endif 67 # include <linux/ipmi.h> 68 # elif defined(HAVE_FREEBSD_IPMI_H) 69 # include <sys/ipmi.h> 70 # else 71 # include "plugins/open/open.h" 72 # endif 73 # include <sys/poll.h> 74 #endif /* IPMI_INTF_OPEN */ 75 76 #include <ipmitool/helper.h> 77 #include <ipmitool/log.h> 78 #include <ipmitool/ipmi.h> 79 #include <ipmitool/ipmi_intf.h> 80 #include <ipmitool/ipmi_sel.h> 81 #include <ipmitool/ipmi_sdr.h> 82 #include <ipmitool/ipmi_strings.h> 83 #include <ipmitool/ipmi_main.h> 84 85 #define WARNING_THRESHOLD 80 86 #define DEFAULT_PIDFILE _PATH_VARRUN "ipmievd.pid" 87 char pidfile[64]; 88 89 /* global variables */ 90 int verbose = 0; 91 int csv_output = 0; 92 uint16_t selwatch_count = 0; /* number of entries in the SEL */ 93 uint16_t selwatch_lastid = 0; /* current last entry in the SEL */ 94 int selwatch_pctused = 0; /* current percent usage in the SEL */ 95 int selwatch_overflow = 0; /* SEL overflow */ 96 int selwatch_timeout = 10; /* default to 10 seconds */ 97 98 /* event interface definition */ 99 struct ipmi_event_intf { 100 char name[16]; 101 char desc[128]; 102 char prefix[72]; 103 int (*setup)(struct ipmi_event_intf * eintf); 104 int (*wait)(struct ipmi_event_intf * eintf); 105 int (*read)(struct ipmi_event_intf * eintf); 106 int (*check)(struct ipmi_event_intf * eintf); 107 void (*log)(struct ipmi_event_intf * eintf, struct sel_event_record * evt); 108 struct ipmi_intf * intf; 109 }; 110 111 /* Data from SEL we are interested in */ 112 typedef struct sel_data { 113 uint16_t entries; 114 int pctused; 115 int overflow; 116 } sel_data; 117 118 static void log_event(struct ipmi_event_intf * eintf, struct sel_event_record * evt); 119 120 /* ~~~~~~~~~~~~~~~~~~~~~~ openipmi ~~~~~~~~~~~~~~~~~~~~ */ 121 #ifdef IPMI_INTF_OPEN 122 static int openipmi_setup(struct ipmi_event_intf * eintf); 123 static int openipmi_wait(struct ipmi_event_intf * eintf); 124 static int openipmi_read(struct ipmi_event_intf * eintf); 125 static struct ipmi_event_intf openipmi_event_intf = { 126 .name = "open", 127 .desc = "OpenIPMI asyncronous notification of events", 128 .prefix = "", 129 .setup = openipmi_setup, 130 .wait = openipmi_wait, 131 .read = openipmi_read, 132 .log = log_event, 133 }; 134 #endif 135 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 136 137 /* ~~~~~~~~~~~~~~~~~~~~~~ selwatch ~~~~~~~~~~~~~~~~~~~~ */ 138 static int selwatch_setup(struct ipmi_event_intf * eintf); 139 static int selwatch_wait(struct ipmi_event_intf * eintf); 140 static int selwatch_read(struct ipmi_event_intf * eintf); 141 static int selwatch_check(struct ipmi_event_intf * eintf); 142 static struct ipmi_event_intf selwatch_event_intf = { 143 .name = "sel", 144 .desc = "Poll SEL for notification of events", 145 .setup = selwatch_setup, 146 .wait = selwatch_wait, 147 .read = selwatch_read, 148 .check = selwatch_check, 149 .log = log_event, 150 }; 151 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 152 153 struct ipmi_event_intf * ipmi_event_intf_table[] = { 154 #ifdef IPMI_INTF_OPEN 155 &openipmi_event_intf, 156 #endif 157 &selwatch_event_intf, 158 NULL 159 }; 160 161 /*************************************************************************/ 162 163 static void 164 ipmievd_usage(void) 165 { 166 lprintf(LOG_NOTICE, "Options:"); 167 lprintf(LOG_NOTICE, "\ttimeout=# Time between checks for SEL polling method [default=10]"); 168 lprintf(LOG_NOTICE, "\tdaemon Become a daemon [default]"); 169 lprintf(LOG_NOTICE, "\tnodaemon Do NOT become a daemon"); 170 } 171 172 /* ipmi_intf_load - Load an event interface from the table above 173 * If no interface name is given return first entry 174 * 175 * @name: interface name to try and load 176 * 177 * returns pointer to inteface structure if found 178 * returns NULL on error 179 */ 180 static struct ipmi_event_intf * 181 ipmi_event_intf_load(char * name) 182 { 183 struct ipmi_event_intf ** intf; 184 struct ipmi_event_intf * i; 185 186 if (name == NULL) { 187 i = ipmi_event_intf_table[0]; 188 return i; 189 } 190 191 for (intf = ipmi_event_intf_table; 192 ((intf != NULL) && (*intf != NULL)); 193 intf++) { 194 i = *intf; 195 if (strncmp(name, i->name, strlen(name)) == 0) { 196 return i; 197 } 198 } 199 200 return NULL; 201 } 202 203 static int 204 compute_pctfull(uint16_t entries, uint16_t freespace) 205 { 206 int pctfull = 0; 207 208 if (entries) { 209 entries *= 16; 210 freespace += entries; 211 pctfull = (int)(100 * ( (double)entries / (double)freespace )); 212 } 213 return pctfull; 214 } 215 216 217 static void 218 log_event(struct ipmi_event_intf * eintf, struct sel_event_record * evt) 219 { 220 char *desc; 221 const char *type; 222 struct sdr_record_list * sdr; 223 struct ipmi_intf * intf = eintf->intf; 224 float trigger_reading = 0.0; 225 float threshold_reading = 0.0; 226 227 if (evt == NULL) 228 return; 229 230 if (evt->record_type == 0xf0) { 231 lprintf(LOG_ALERT, "%sLinux kernel panic: %.11s", 232 eintf->prefix, (char *) evt + 5); 233 return; 234 } 235 else if (evt->record_type >= 0xc0) { 236 lprintf(LOG_NOTICE, "%sIPMI Event OEM Record %02x", 237 eintf->prefix, evt->record_type); 238 return; 239 } 240 241 type = ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, 242 evt->sel_type.standard_type.event_data[0]); 243 244 ipmi_get_event_desc(intf, evt, &desc); 245 246 sdr = ipmi_sdr_find_sdr_bynumtype(intf, evt->sel_type.standard_type.gen_id, evt->sel_type.standard_type.sensor_num, 247 evt->sel_type.standard_type.sensor_type); 248 249 if (sdr == NULL) { 250 /* could not find matching SDR record */ 251 if (desc) { 252 lprintf(LOG_NOTICE, "%s%s sensor - %s", 253 eintf->prefix, type, desc); 254 free(desc); 255 desc = NULL; 256 } else { 257 lprintf(LOG_NOTICE, "%s%s sensor %02x", 258 eintf->prefix, type, 259 evt->sel_type.standard_type.sensor_num); 260 } 261 return; 262 } 263 264 switch (sdr->type) { 265 case SDR_RECORD_TYPE_FULL_SENSOR: 266 if (evt->sel_type.standard_type.event_type == 1) { 267 /* 268 * Threshold Event 269 */ 270 271 /* trigger reading in event data byte 2 */ 272 if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) { 273 trigger_reading = sdr_convert_sensor_reading( 274 sdr->record.full, evt->sel_type.standard_type.event_data[1]); 275 } 276 277 /* trigger threshold in event data byte 3 */ 278 if (((evt->sel_type.standard_type.event_data[0] >> 4) & 3) == 1) { 279 threshold_reading = sdr_convert_sensor_reading( 280 sdr->record.full, evt->sel_type.standard_type.event_data[2]); 281 } 282 283 lprintf(LOG_NOTICE, "%s%s sensor %s %s %s (Reading %.*f %s Threshold %.*f %s)", 284 eintf->prefix, 285 type, 286 sdr->record.full->id_string, 287 desc ? desc : "", 288 (evt->sel_type.standard_type.event_dir 289 ? "Deasserted" : "Asserted"), 290 (trigger_reading==(int)trigger_reading) ? 0 : 2, 291 trigger_reading, 292 ((evt->sel_type.standard_type.event_data[0] & 0xf) % 2) ? ">" : "<", 293 (threshold_reading==(int)threshold_reading) ? 0 : 2, 294 threshold_reading, 295 ipmi_sdr_get_unit_string(sdr->record.common->unit.pct, 296 sdr->record.common->unit.modifier, 297 sdr->record.common->unit.type.base, 298 sdr->record.common->unit.type.modifier)); 299 } 300 else if ((evt->sel_type.standard_type.event_type >= 0x2 && evt->sel_type.standard_type.event_type <= 0xc) || 301 (evt->sel_type.standard_type.event_type == 0x6f)) { 302 /* 303 * Discrete Event 304 */ 305 lprintf(LOG_NOTICE, "%s%s sensor %s %s %s", 306 eintf->prefix, type, 307 sdr->record.full->id_string, desc ? desc : "", 308 (evt->sel_type.standard_type.event_dir 309 ? "Deasserted" : "Asserted")); 310 if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) { 311 /* previous state and/or severity in event data byte 2 */ 312 } 313 } 314 else if (evt->sel_type.standard_type.event_type >= 0x70 && evt->sel_type.standard_type.event_type <= 0x7f) { 315 /* 316 * OEM Event 317 */ 318 lprintf(LOG_NOTICE, "%s%s sensor %s %s %s", 319 eintf->prefix, type, 320 sdr->record.full->id_string, desc ? desc : "", 321 (evt->sel_type.standard_type.event_dir 322 ? "Deasserted" : "Asserted")); 323 } 324 break; 325 326 case SDR_RECORD_TYPE_COMPACT_SENSOR: 327 lprintf(LOG_NOTICE, "%s%s sensor %s - %s %s", 328 eintf->prefix, type, 329 sdr->record.compact->id_string, desc ? desc : "", 330 (evt->sel_type.standard_type.event_dir 331 ? "Deasserted" : "Asserted")); 332 break; 333 334 default: 335 lprintf(LOG_NOTICE, "%s%s sensor - %s", 336 eintf->prefix, type, 337 evt->sel_type.standard_type.sensor_num, desc ? desc : ""); 338 break; 339 } 340 341 if (desc) { 342 free(desc); 343 desc = NULL; 344 } 345 } 346 /*************************************************************************/ 347 348 349 /*************************************************************************/ 350 /** OpenIPMI Functions **/ 351 /*************************************************************************/ 352 #ifdef IPMI_INTF_OPEN 353 static int 354 openipmi_enable_event_msg_buffer(struct ipmi_intf * intf) 355 { 356 struct ipmi_rs * rsp; 357 struct ipmi_rq req; 358 uint8_t bmc_global_enables; 359 360 /* we must read/modify/write bmc global enables */ 361 memset(&req, 0, sizeof(req)); 362 req.msg.netfn = IPMI_NETFN_APP; 363 req.msg.cmd = 0x2f; /* Get BMC Global Enables */ 364 365 rsp = intf->sendrecv(intf, &req); 366 if (rsp == NULL) { 367 lprintf(LOG_ERR, "Get BMC Global Enables command failed"); 368 return -1; 369 } 370 else if (rsp->ccode > 0) { 371 lprintf(LOG_ERR, "Get BMC Global Enables command failed: %s", 372 val2str(rsp->ccode, completion_code_vals)); 373 return -1; 374 } 375 376 bmc_global_enables = rsp->data[0] | 0x04; 377 req.msg.cmd = 0x2e; /* Set BMC Global Enables */ 378 req.msg.data = &bmc_global_enables; 379 req.msg.data_len = 1; 380 381 rsp = intf->sendrecv(intf, &req); 382 if (rsp == NULL) { 383 lprintf(LOG_ERR, "Set BMC Global Enables command failed"); 384 return -1; 385 } 386 else if (rsp->ccode > 0) { 387 lprintf(LOG_ERR, "Set BMC Global Enables command failed: %s", 388 val2str(rsp->ccode, completion_code_vals)); 389 return -1; 390 } 391 392 lprintf(LOG_DEBUG, "BMC Event Message Buffer enabled"); 393 394 return 0; 395 } 396 397 static int 398 openipmi_setup(struct ipmi_event_intf * eintf) 399 { 400 int i, r; 401 402 /* enable event message buffer */ 403 lprintf(LOG_DEBUG, "Enabling event message buffer"); 404 r = openipmi_enable_event_msg_buffer(eintf->intf); 405 if (r < 0) { 406 lprintf(LOG_ERR, "Could not enable event message buffer"); 407 return -1; 408 } 409 410 /* enable OpenIPMI event receiver */ 411 lprintf(LOG_DEBUG, "Enabling event receiver"); 412 i = 1; 413 r = ioctl(eintf->intf->fd, IPMICTL_SET_GETS_EVENTS_CMD, &i); 414 if (r != 0) { 415 lperror(LOG_ERR, "Could not enable event receiver"); 416 return -1; 417 } 418 419 return 0; 420 } 421 422 static int 423 openipmi_read(struct ipmi_event_intf * eintf) 424 { 425 struct ipmi_addr addr; 426 struct ipmi_recv recv; 427 uint8_t data[80]; 428 int rv; 429 430 recv.addr = (unsigned char *) &addr; 431 recv.addr_len = sizeof(addr); 432 recv.msg.data = data; 433 recv.msg.data_len = sizeof(data); 434 435 rv = ioctl(eintf->intf->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv); 436 if (rv < 0) { 437 switch (errno) { 438 case EINTR: 439 return 0; /* abort */ 440 case EMSGSIZE: 441 recv.msg.data_len = sizeof(data); /* truncated */ 442 break; 443 default: 444 lperror(LOG_ERR, "Unable to receive IPMI message"); 445 return -1; 446 } 447 } 448 449 if (!recv.msg.data || recv.msg.data_len == 0) { 450 lprintf(LOG_ERR, "No data in event"); 451 return -1; 452 } 453 if (recv.recv_type != IPMI_ASYNC_EVENT_RECV_TYPE) { 454 lprintf(LOG_ERR, "Type %x is not an event", recv.recv_type); 455 return -1; 456 } 457 458 lprintf(LOG_DEBUG, "netfn:%x cmd:%x ccode:%d", 459 recv.msg.netfn, recv.msg.cmd, recv.msg.data[0]); 460 461 eintf->log(eintf, (struct sel_event_record *)recv.msg.data); 462 463 return 0; 464 } 465 466 static int 467 openipmi_wait(struct ipmi_event_intf * eintf) 468 { 469 struct pollfd pfd; 470 int r; 471 472 for (;;) { 473 pfd.fd = eintf->intf->fd; /* wait on openipmi device */ 474 pfd.events = POLLIN; /* wait for input */ 475 r = poll(&pfd, 1, -1); 476 477 switch (r) { 478 case 0: 479 /* timeout is disabled */ 480 break; 481 case -1: 482 lperror(LOG_CRIT, "Unable to read from IPMI device"); 483 return -1; 484 default: 485 if (pfd.revents & POLLIN) 486 eintf->read(eintf); 487 } 488 } 489 490 return 0; 491 } 492 #endif /* IPMI_INTF_OPEN */ 493 /*************************************************************************/ 494 495 496 /*************************************************************************/ 497 /** SEL Watch Functions **/ 498 /*************************************************************************/ 499 static int 500 selwatch_get_data(struct ipmi_intf * intf, struct sel_data *data) 501 { 502 struct ipmi_rs * rsp; 503 struct ipmi_rq req; 504 uint16_t freespace; 505 506 memset(&req, 0, sizeof(req)); 507 req.msg.netfn = IPMI_NETFN_STORAGE; 508 req.msg.cmd = IPMI_CMD_GET_SEL_INFO; 509 510 rsp = intf->sendrecv(intf, &req); 511 if (rsp == NULL) { 512 lprintf(LOG_ERR, "Get SEL Info command failed"); 513 return 0; 514 } 515 if (rsp->ccode > 0) { 516 lprintf(LOG_ERR, "Get SEL Info command failed: %s", 517 val2str(rsp->ccode, completion_code_vals)); 518 return 0; 519 } 520 521 freespace = buf2short(rsp->data + 3); 522 data->entries = buf2short(rsp->data + 1); 523 data->pctused = compute_pctfull (data->entries, freespace); 524 data->overflow = rsp->data[13] & 0x80; 525 526 lprintf(LOG_DEBUG, "SEL count is %d", data->entries); 527 lprintf(LOG_DEBUG, "SEL freespace is %d", freespace); 528 lprintf(LOG_DEBUG, "SEL Percent Used: %d%%\n", data->pctused); 529 lprintf(LOG_DEBUG, "SEL Overflow: %s", data->overflow ? "true" : "false"); 530 531 return 1; 532 } 533 534 static uint16_t 535 selwatch_get_lastid(struct ipmi_intf * intf) 536 { 537 int next_id = 0; 538 uint16_t curr_id = 0; 539 struct sel_event_record evt; 540 541 if (selwatch_count == 0) 542 return 0; 543 544 while (next_id != 0xffff) { 545 curr_id = next_id; 546 lprintf(LOG_DEBUG, "SEL Next ID: %04x", curr_id); 547 548 next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt); 549 if (next_id < 0) 550 break; 551 if (next_id == 0) { 552 /* 553 * usually next_id of zero means end but 554 * retry because some hardware has quirks 555 * and will return 0 randomly. 556 */ 557 next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt); 558 if (next_id <= 0) 559 break; 560 } 561 } 562 563 lprintf(LOG_DEBUG, "SEL lastid is %04x", curr_id); 564 565 return curr_id; 566 } 567 568 static int 569 selwatch_setup(struct ipmi_event_intf * eintf) 570 { 571 struct sel_data data; 572 573 /* save current sel record count */ 574 if (selwatch_get_data(eintf->intf, &data)) { 575 selwatch_count = data.entries; 576 selwatch_pctused = data.pctused; 577 selwatch_overflow = data.overflow; 578 lprintf(LOG_DEBUG, "Current SEL count is %d", selwatch_count); 579 /* save current last record ID */ 580 selwatch_lastid = selwatch_get_lastid(eintf->intf); 581 lprintf(LOG_DEBUG, "Current SEL lastid is %04x", selwatch_lastid); 582 /* display alert/warning immediatly as startup if relevant */ 583 if (selwatch_pctused >= WARNING_THRESHOLD) { 584 lprintf(LOG_WARNING, "SEL buffer used at %d%%, please consider clearing the SEL buffer", selwatch_pctused); 585 } 586 if (selwatch_overflow) { 587 lprintf(LOG_ALERT, "SEL buffer overflow, no SEL message can be logged until the SEL buffer is cleared"); 588 } 589 590 return 1; 591 } 592 593 lprintf(LOG_ERR, "Unable to retrieve SEL data"); 594 return 0; 595 } 596 597 /* selwatch_check - check for waiting events 598 * 599 * this is done by reading sel info and comparing 600 * the sel count value to what we currently know 601 */ 602 static int 603 selwatch_check(struct ipmi_event_intf * eintf) 604 { 605 uint16_t old_count = selwatch_count; 606 int old_pctused = selwatch_pctused; 607 int old_overflow = selwatch_overflow; 608 struct sel_data data; 609 610 if (selwatch_get_data(eintf->intf, &data)) { 611 selwatch_count = data.entries; 612 selwatch_pctused = data.pctused; 613 selwatch_overflow = data.overflow; 614 if (old_overflow && !selwatch_overflow) { 615 lprintf(LOG_NOTICE, "SEL overflow is cleared"); 616 } else if (!old_overflow && selwatch_overflow) { 617 lprintf(LOG_ALERT, "SEL buffer overflow, no new SEL message will be logged until the SEL buffer is cleared"); 618 } 619 if ((selwatch_pctused >= WARNING_THRESHOLD) && (selwatch_pctused > old_pctused)) { 620 lprintf(LOG_WARNING, "SEL buffer is %d%% full, please consider clearing the SEL buffer", selwatch_pctused); 621 } 622 if (selwatch_count == 0) { 623 lprintf(LOG_DEBUG, "SEL count is 0 (old=%d), resetting lastid to 0", old_count); 624 selwatch_lastid = 0; 625 } else if (selwatch_count < old_count) { 626 selwatch_lastid = selwatch_get_lastid(eintf->intf); 627 lprintf(LOG_DEBUG, "SEL count lowered, new SEL lastid is %04x", selwatch_lastid); 628 } 629 } 630 return (selwatch_count > old_count); 631 } 632 633 static int 634 selwatch_read(struct ipmi_event_intf * eintf) 635 { 636 uint16_t curr_id = 0; 637 int next_id = selwatch_lastid; 638 struct sel_event_record evt; 639 640 if (selwatch_count == 0) 641 return -1; 642 643 while (next_id != 0xffff) { 644 curr_id = next_id; 645 lprintf(LOG_DEBUG, "SEL Read ID: %04x", curr_id); 646 647 next_id = ipmi_sel_get_std_entry(eintf->intf, curr_id, &evt); 648 if (next_id < 0) 649 break; 650 if (next_id == 0) { 651 /* 652 * usually next_id of zero means end but 653 * retry because some hardware has quirks 654 * and will return 0 randomly. 655 */ 656 next_id = ipmi_sel_get_std_entry(eintf->intf, curr_id, &evt); 657 if (next_id <= 0) 658 break; 659 } 660 661 if (curr_id != selwatch_lastid) 662 eintf->log(eintf, &evt); 663 else if (curr_id == 0) 664 eintf->log(eintf, &evt); 665 } 666 667 selwatch_lastid = curr_id; 668 return 0; 669 } 670 671 static int 672 selwatch_wait(struct ipmi_event_intf * eintf) 673 { 674 for (;;) { 675 if (eintf->check(eintf) > 0) { 676 lprintf(LOG_DEBUG, "New Events"); 677 eintf->read(eintf); 678 } 679 sleep(selwatch_timeout); 680 } 681 return 0; 682 } 683 /*************************************************************************/ 684 685 static void 686 ipmievd_cleanup(int signal) 687 { 688 struct stat st1; 689 690 if (lstat(pidfile, &st1) == 0) { 691 /* cleanup daemon pidfile */ 692 (void)unlink(pidfile); 693 } 694 695 exit(EXIT_SUCCESS); 696 } 697 698 int 699 ipmievd_main(struct ipmi_event_intf * eintf, int argc, char ** argv) 700 { 701 int i, rc; 702 int daemon = 1; 703 struct sigaction act; 704 705 memset(pidfile, 0, 64); 706 sprintf(pidfile, "%s%d", DEFAULT_PIDFILE, eintf->intf->devnum); 707 lprintf(LOG_NOTICE, "ipmievd: using pidfile %s", pidfile); 708 709 for (i = 0; i < argc; i++) { 710 if (strncasecmp(argv[i], "help", 4) == 0) { 711 ipmievd_usage(); 712 return 0; 713 } 714 if (strncasecmp(argv[i], "daemon", 6) == 0) { 715 daemon = 1; 716 } 717 else if (strncasecmp(argv[i], "nodaemon", 8) == 0) { 718 daemon = 0; 719 } 720 else if (strncasecmp(argv[i], "daemon=", 7) == 0) { 721 if (strncasecmp(argv[i]+7, "on", 2) == 0 || 722 strncasecmp(argv[i]+7, "yes", 3) == 0) 723 daemon = 1; 724 else if (strncasecmp(argv[i]+7, "off", 3) == 0 || 725 strncasecmp(argv[i]+7, "no", 2) == 0) 726 daemon = 0; 727 } 728 else if (strncasecmp(argv[i], "timeout=", 8) == 0) { 729 if ( (str2int(argv[i]+8, &selwatch_timeout) != 0) || 730 selwatch_timeout < 0) { 731 lprintf(LOG_ERR, "Invalid input given or out of range for time-out."); 732 return (-1); 733 } 734 } 735 else if (strncasecmp(argv[i], "pidfile=", 8) == 0) { 736 memset(pidfile, 0, 64); 737 strncpy(pidfile, argv[i]+8, 738 __min(strlen((const char *)(argv[i]+8)), 63)); 739 } 740 } 741 742 /* 743 * We need to open interface before forking daemon 744 * so error messages are not lost to syslog and 745 * return code is successfully returned to initscript 746 */ 747 if (eintf->intf->open(eintf->intf) < 0) { 748 lprintf(LOG_ERR, "Unable to open interface"); 749 return -1; 750 } 751 752 if (daemon) { 753 FILE *fp; 754 struct stat st1; 755 756 if (lstat(pidfile, &st1) == 0) { 757 /* PID file already exists -> exit. */ 758 lprintf(LOG_ERR, "PID file '%s' already exists.", pidfile); 759 lprintf(LOG_ERR, "Perhaps another instance is already running."); 760 return (-1); 761 } 762 763 ipmi_start_daemon(eintf->intf); 764 765 umask(022); 766 fp = ipmi_open_file_write(pidfile); 767 if (fp == NULL) { 768 /* Failed to get fp on PID file -> exit. */ 769 log_halt(); 770 log_init("ipmievd", daemon, verbose); 771 lprintf(LOG_ERR, 772 "Failed to open PID file '%s' for writing. Check file permission.", 773 pidfile); 774 exit(EXIT_FAILURE); 775 } 776 fprintf(fp, "%d\n", (int)getpid()); 777 fclose(fp); 778 } 779 780 /* register signal handler for cleanup */ 781 act.sa_handler = ipmievd_cleanup; 782 act.sa_flags = 0; 783 sigemptyset(&act.sa_mask); 784 sigaction(SIGINT, &act, NULL); 785 sigaction(SIGQUIT, &act, NULL); 786 sigaction(SIGTERM, &act, NULL); 787 788 log_halt(); 789 log_init("ipmievd", daemon, verbose); 790 791 /* generate SDR cache for fast lookups */ 792 lprintf(LOG_NOTICE, "Reading sensors..."); 793 ipmi_sdr_list_cache(eintf->intf); 794 lprintf(LOG_DEBUG, "Sensors cached"); 795 796 /* call event handler setup routine */ 797 798 if (eintf->setup != NULL) { 799 rc = eintf->setup(eintf); 800 if (rc < 0) { 801 lprintf(LOG_ERR, "Error setting up Event Interface %s", eintf->name); 802 return -1; 803 } 804 } 805 806 lprintf(LOG_NOTICE, "Waiting for events..."); 807 808 /* now launch event wait loop */ 809 if (eintf->wait != NULL) { 810 rc = eintf->wait(eintf); 811 if (rc < 0) { 812 lprintf(LOG_ERR, "Error waiting for events!"); 813 return -1; 814 } 815 } 816 817 return 0; 818 } 819 820 int 821 ipmievd_sel_main(struct ipmi_intf * intf, int argc, char ** argv) 822 { 823 struct ipmi_event_intf * eintf; 824 825 eintf = ipmi_event_intf_load("sel"); 826 if (eintf == NULL) { 827 lprintf(LOG_ERR, "Unable to load event interface"); 828 return -1; 829 } 830 831 eintf->intf = intf; 832 833 if (intf->session != NULL) { 834 snprintf(eintf->prefix, 835 strlen((const char *)intf->session->hostname) + 3, 836 "%s: ", intf->session->hostname); 837 } 838 839 return ipmievd_main(eintf, argc, argv); 840 } 841 842 int 843 ipmievd_open_main(struct ipmi_intf * intf, int argc, char ** argv) 844 { 845 struct ipmi_event_intf * eintf; 846 847 /* only one interface works for this */ 848 if (strncmp(intf->name, "open", 4) != 0) { 849 lprintf(LOG_ERR, "Invalid Interface for OpenIPMI Event Handler: %s", intf->name); 850 return -1; 851 } 852 853 eintf = ipmi_event_intf_load("open"); 854 if (eintf == NULL) { 855 lprintf(LOG_ERR, "Unable to load event interface"); 856 return -1; 857 } 858 859 eintf->intf = intf; 860 861 return ipmievd_main(eintf, argc, argv); 862 } 863 864 struct ipmi_cmd ipmievd_cmd_list[] = { 865 #ifdef IPMI_INTF_OPEN 866 { ipmievd_open_main, "open", "Use OpenIPMI for asyncronous notification of events" }, 867 #endif 868 { ipmievd_sel_main, "sel", "Poll SEL for notification of events" }, 869 { NULL } 870 }; 871 872 int main(int argc, char ** argv) 873 { 874 int rc; 875 876 rc = ipmi_main(argc, argv, ipmievd_cmd_list, NULL); 877 878 if (rc < 0) 879 exit(EXIT_FAILURE); 880 else 881 exit(EXIT_SUCCESS); 882 } 883