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