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