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
ipmievd_usage(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 *
ipmi_event_intf_load(char * name)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
compute_pctfull(uint16_t entries,uint16_t freespace)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
log_event(struct ipmi_event_intf * eintf,struct sel_event_record * evt)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
openipmi_enable_event_msg_buffer(struct ipmi_intf * intf)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
openipmi_setup(struct ipmi_event_intf * eintf)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
openipmi_read(struct ipmi_event_intf * eintf)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
openipmi_wait(struct ipmi_event_intf * eintf)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
selwatch_get_data(struct ipmi_intf * intf,struct sel_data * data)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
selwatch_get_lastid(struct ipmi_intf * intf)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
selwatch_setup(struct ipmi_event_intf * eintf)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
selwatch_check(struct ipmi_event_intf * eintf)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
selwatch_read(struct ipmi_event_intf * eintf)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
selwatch_wait(struct ipmi_event_intf * eintf)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
ipmievd_cleanup(int signal)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
ipmievd_main(struct ipmi_event_intf * eintf,int argc,char ** argv)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
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 lprintf(LOG_DEBUG, "ipmievd: using pidfile %s", pidfile);
742
743 /*
744 * We need to open interface before forking daemon
745 * so error messages are not lost to syslog and
746 * return code is successfully returned to initscript
747 */
748 if (eintf->intf->open(eintf->intf) < 0) {
749 lprintf(LOG_ERR, "Unable to open interface");
750 return -1;
751 }
752
753 if (daemon) {
754 FILE *fp;
755 struct stat st1;
756
757 if (lstat(pidfile, &st1) == 0) {
758 /* PID file already exists -> exit. */
759 lprintf(LOG_ERR, "PID file '%s' already exists.", pidfile);
760 lprintf(LOG_ERR, "Perhaps another instance is already running.");
761 return (-1);
762 }
763
764 ipmi_start_daemon(eintf->intf);
765
766 umask(022);
767 fp = ipmi_open_file_write(pidfile);
768 if (fp == NULL) {
769 /* Failed to get fp on PID file -> exit. */
770 log_halt();
771 log_init("ipmievd", daemon, verbose);
772 lprintf(LOG_ERR,
773 "Failed to open PID file '%s' for writing. Check file permission.",
774 pidfile);
775 exit(EXIT_FAILURE);
776 }
777 fprintf(fp, "%d\n", (int)getpid());
778 fclose(fp);
779 }
780
781 /* register signal handler for cleanup */
782 act.sa_handler = ipmievd_cleanup;
783 act.sa_flags = 0;
784 sigemptyset(&act.sa_mask);
785 sigaction(SIGINT, &act, NULL);
786 sigaction(SIGQUIT, &act, NULL);
787 sigaction(SIGTERM, &act, NULL);
788
789 log_halt();
790 log_init("ipmievd", daemon, verbose);
791
792 /* generate SDR cache for fast lookups */
793 lprintf(LOG_NOTICE, "Reading sensors...");
794 ipmi_sdr_list_cache(eintf->intf);
795 lprintf(LOG_DEBUG, "Sensors cached");
796
797 /* call event handler setup routine */
798
799 if (eintf->setup != NULL) {
800 rc = eintf->setup(eintf);
801 if (rc < 0) {
802 lprintf(LOG_ERR, "Error setting up Event Interface %s", eintf->name);
803 return -1;
804 }
805 }
806
807 lprintf(LOG_NOTICE, "Waiting for events...");
808
809 /* now launch event wait loop */
810 if (eintf->wait != NULL) {
811 rc = eintf->wait(eintf);
812 if (rc < 0) {
813 lprintf(LOG_ERR, "Error waiting for events!");
814 return -1;
815 }
816 }
817
818 return 0;
819 }
820
821 int
ipmievd_sel_main(struct ipmi_intf * intf,int argc,char ** argv)822 ipmievd_sel_main(struct ipmi_intf * intf, int argc, char ** argv)
823 {
824 struct ipmi_event_intf * eintf;
825
826 eintf = ipmi_event_intf_load("sel");
827 if (eintf == NULL) {
828 lprintf(LOG_ERR, "Unable to load event interface");
829 return -1;
830 }
831
832 eintf->intf = intf;
833
834 if (intf->session != NULL) {
835 snprintf(eintf->prefix,
836 strlen((const char *)intf->ssn_params.hostname) + 3,
837 "%s: ", intf->ssn_params.hostname);
838 }
839
840 return ipmievd_main(eintf, argc, argv);
841 }
842
843 int
ipmievd_open_main(struct ipmi_intf * intf,int argc,char ** argv)844 ipmievd_open_main(struct ipmi_intf * intf, int argc, char ** argv)
845 {
846 struct ipmi_event_intf * eintf;
847
848 /* only one interface works for this */
849 if (strncmp(intf->name, "open", 4) != 0) {
850 lprintf(LOG_ERR, "Invalid Interface for OpenIPMI Event Handler: %s", intf->name);
851 return -1;
852 }
853
854 eintf = ipmi_event_intf_load("open");
855 if (eintf == NULL) {
856 lprintf(LOG_ERR, "Unable to load event interface");
857 return -1;
858 }
859
860 eintf->intf = intf;
861
862 return ipmievd_main(eintf, argc, argv);
863 }
864
865 struct ipmi_cmd ipmievd_cmd_list[] = {
866 #ifdef IPMI_INTF_OPEN
867 { ipmievd_open_main, "open", "Use OpenIPMI for asyncronous notification of events" },
868 #endif
869 { ipmievd_sel_main, "sel", "Poll SEL for notification of events" },
870 { NULL }
871 };
872
main(int argc,char ** argv)873 int main(int argc, char ** argv)
874 {
875 int rc;
876
877 rc = ipmi_main(argc, argv, ipmievd_cmd_list, NULL);
878
879 if (rc < 0)
880 exit(EXIT_FAILURE);
881 else
882 exit(EXIT_SUCCESS);
883 }
884