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