xref: /openbmc/ipmitool/src/ipmievd.c (revision 531569ec)
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