xref: /openbmc/ipmitool/lib/ipmi_event.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 <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <signal.h>
43 #include <ctype.h>
44 
45 #include <ipmitool/ipmi.h>
46 #include <ipmitool/ipmi_intf.h>
47 #include <ipmitool/helper.h>
48 #include <ipmitool/log.h>
49 #include <ipmitool/ipmi_sel.h>
50 #include <ipmitool/ipmi_strings.h>
51 #include <ipmitool/ipmi_channel.h>
52 #include <ipmitool/ipmi_event.h>
53 #include <ipmitool/ipmi_sdr.h>
54 
55 
56 static void
ipmi_event_msg_print(struct ipmi_intf * intf,struct platform_event_msg * pmsg)57 ipmi_event_msg_print(struct ipmi_intf * intf, struct platform_event_msg * pmsg)
58 {
59 	struct sel_event_record sel_event;
60 
61 	memset(&sel_event, 0, sizeof(struct sel_event_record));
62 
63 	sel_event.record_id = 0;
64 	sel_event.sel_type.standard_type.gen_id = 2;
65 
66 	sel_event.sel_type.standard_type.evm_rev        = pmsg->evm_rev;
67 	sel_event.sel_type.standard_type.sensor_type    = pmsg->sensor_type;
68 	sel_event.sel_type.standard_type.sensor_num     = pmsg->sensor_num;
69 	sel_event.sel_type.standard_type.event_type     = pmsg->event_type;
70 	sel_event.sel_type.standard_type.event_dir      = pmsg->event_dir;
71 	sel_event.sel_type.standard_type.event_data[0]  = pmsg->event_data[0];
72 	sel_event.sel_type.standard_type.event_data[1]  = pmsg->event_data[1];
73 	sel_event.sel_type.standard_type.event_data[2]  = pmsg->event_data[2];
74 
75 	if (verbose)
76 		ipmi_sel_print_extended_entry_verbose(intf, &sel_event);
77 	else
78 		ipmi_sel_print_extended_entry(intf, &sel_event);
79 }
80 
81 static int
ipmi_send_platform_event(struct ipmi_intf * intf,struct platform_event_msg * emsg)82 ipmi_send_platform_event(struct ipmi_intf * intf, struct platform_event_msg * emsg)
83 {
84 	struct ipmi_rs * rsp;
85 	struct ipmi_rq req;
86 	uint8_t rqdata[8];
87 	uint8_t chmed;
88 
89 	memset(&req, 0, sizeof(req));
90 	memset(rqdata, 0, 8);
91 
92 	req.msg.netfn = IPMI_NETFN_SE;
93 	req.msg.cmd = 0x02;
94 	req.msg.data = rqdata;
95 
96 	chmed = ipmi_current_channel_medium(intf);
97 	if (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM) {
98 		/* system interface, need extra generator ID */
99 		req.msg.data_len = 8;
100 		rqdata[0] = 0x41;   // As per Fig. 29-2 and Table 5-4
101 		memcpy(rqdata+1, emsg, sizeof(struct platform_event_msg));
102 	}
103 	else {
104 		req.msg.data_len = 7;
105 		memcpy(rqdata, emsg, sizeof(struct platform_event_msg));
106 	}
107 
108 	ipmi_event_msg_print(intf, emsg);
109 
110 	rsp = intf->sendrecv(intf, &req);
111 	if (rsp == NULL) {
112 		lprintf(LOG_ERR, "Platform Event Message command failed");
113 		return -1;
114 	}
115 	else if (rsp->ccode > 0) {
116 		lprintf(LOG_ERR, "Platform Event Message command failed: %s",
117 			val2str(rsp->ccode, completion_code_vals));
118 		return -1;
119 	}
120 
121 	return 0;
122 }
123 
124 #define EVENT_THRESH_STATE_LNC_LO	0
125 #define EVENT_THRESH_STATE_LNC_HI	1
126 #define EVENT_THRESH_STATE_LCR_LO	2
127 #define EVENT_THRESH_STATE_LCR_HI	3
128 #define EVENT_THRESH_STATE_LNR_LO	4
129 #define EVENT_THRESH_STATE_LNR_HI	5
130 #define EVENT_THRESH_STATE_UNC_LO	6
131 #define EVENT_THRESH_STATE_UNC_HI	7
132 #define EVENT_THRESH_STATE_UCR_LO	8
133 #define EVENT_THRESH_STATE_UCR_HI	9
134 #define EVENT_THRESH_STATE_UNR_LO	10
135 #define EVENT_THRESH_STATE_UNR_HI	11
136 
137 static const struct valstr ipmi_event_thresh_lo[] = {
138 	{ EVENT_THRESH_STATE_LNC_LO, "lnc" },
139 	{ EVENT_THRESH_STATE_LCR_LO, "lcr" },
140 	{ EVENT_THRESH_STATE_LNR_LO, "lnr" },
141 	{ EVENT_THRESH_STATE_UNC_LO, "unc" },
142 	{ EVENT_THRESH_STATE_UCR_LO, "ucr" },
143 	{ EVENT_THRESH_STATE_UNR_LO, "unr" },
144 	{ 0, NULL  },
145 };
146 static const struct valstr ipmi_event_thresh_hi[] = {
147 	{ EVENT_THRESH_STATE_LNC_HI, "lnc" },
148 	{ EVENT_THRESH_STATE_LCR_HI, "lcr" },
149 	{ EVENT_THRESH_STATE_LNR_HI, "lnr" },
150 	{ EVENT_THRESH_STATE_UNC_HI, "unc" },
151 	{ EVENT_THRESH_STATE_UCR_HI, "ucr" },
152 	{ EVENT_THRESH_STATE_UNR_HI, "unr" },
153 	{ 0, NULL  },
154 };
155 
156 static int
ipmi_send_platform_event_num(struct ipmi_intf * intf,int num)157 ipmi_send_platform_event_num(struct ipmi_intf * intf, int num)
158 {
159 	struct platform_event_msg emsg;
160 
161 	memset(&emsg, 0, sizeof(struct platform_event_msg));
162 
163 	/* IPMB/LAN/etc */
164 	switch (num) {
165 	case 1:			/* temperature */
166 		printf("Sending SAMPLE event: Temperature - "
167 		       "Upper Critical - Going High\n");
168 		emsg.evm_rev       = 0x04;
169 		emsg.sensor_type   = 0x01;
170 		emsg.sensor_num    = 0x30;
171 		emsg.event_dir     = EVENT_DIR_ASSERT;
172 		emsg.event_type    = 0x01;
173 		emsg.event_data[0] = EVENT_THRESH_STATE_UCR_HI;
174 		emsg.event_data[1] = 0xff;
175 		emsg.event_data[2] = 0xff;
176 		break;
177 	case 2:			/* voltage error */
178 		printf("Sending SAMPLE event: Voltage Threshold - "
179 		       "Lower Critical - Going Low\n");
180 		emsg.evm_rev       = 0x04;
181 		emsg.sensor_type   = 0x02;
182 		emsg.sensor_num    = 0x60;
183 		emsg.event_dir     = EVENT_DIR_ASSERT;
184 		emsg.event_type    = 0x01;
185 		emsg.event_data[0] = EVENT_THRESH_STATE_LCR_LO;
186 		emsg.event_data[1] = 0xff;
187 		emsg.event_data[2] = 0xff;
188 		break;
189 	case 3:			/* correctable ECC */
190 		printf("Sending SAMPLE event: Memory - Correctable ECC\n");
191 		emsg.evm_rev       = 0x04;
192 		emsg.sensor_type   = 0x0c;
193 		emsg.sensor_num    = 0x53;
194 		emsg.event_dir     = EVENT_DIR_ASSERT;
195 		emsg.event_type    = 0x6f;
196 		emsg.event_data[0] = 0x00;
197 		emsg.event_data[1] = 0xff;
198 		emsg.event_data[2] = 0xff;
199 		break;
200 	default:
201 		lprintf(LOG_ERR, "Invalid event number: %d", num);
202 		return -1;
203 	}
204 
205 	return ipmi_send_platform_event(intf, &emsg);
206 }
207 
208 static int
ipmi_event_find_offset(uint8_t code,struct ipmi_event_sensor_types * evt,char * desc)209 ipmi_event_find_offset(uint8_t code,
210 		       struct ipmi_event_sensor_types * evt,
211 		       char * desc)
212 {
213 	if (desc == NULL || code == 0)
214 		return 0x00;
215 
216 	while (evt->type) {
217 		if (evt->code == code && evt->desc != NULL &&
218 		    strncasecmp(desc, evt->desc, __maxlen(desc, evt->desc)) == 0)
219 			return evt->offset;
220 		evt++;
221 	}
222 
223 	lprintf(LOG_WARN, "Unable to find matching event offset for '%s'", desc);
224 	return -1;
225 }
226 
227 static void
print_sensor_states(uint8_t sensor_type,uint8_t event_type)228 print_sensor_states(uint8_t sensor_type, uint8_t event_type)
229 {
230 	ipmi_sdr_print_discrete_state_mini(
231 			"Sensor States: \n  ", "\n  ", sensor_type,
232 					   event_type, 0xff, 0xff);
233 	printf("\n");
234 }
235 
236 
237 static int
ipmi_event_fromsensor(struct ipmi_intf * intf,char * id,char * state,char * evdir)238 ipmi_event_fromsensor(struct ipmi_intf * intf, char * id, char * state, char * evdir)
239 {
240 	struct ipmi_rs * rsp;
241 	struct sdr_record_list * sdr;
242 	struct platform_event_msg emsg;
243 	int off;
244 	uint8_t target, lun, channel;
245 
246 	if (id == NULL) {
247 		lprintf(LOG_ERR, "No sensor ID supplied");
248 		return -1;
249 	}
250 
251 	memset(&emsg, 0, sizeof(struct platform_event_msg));
252 	emsg.evm_rev = 0x04;
253 
254 	if (evdir == NULL)
255 		emsg.event_dir = EVENT_DIR_ASSERT;
256 	else if (strncasecmp(evdir, "assert", 6) == 0)
257 		emsg.event_dir = EVENT_DIR_ASSERT;
258 	else if (strncasecmp(evdir, "deassert", 8) == 0)
259 		emsg.event_dir = EVENT_DIR_DEASSERT;
260 	else {
261 		lprintf(LOG_ERR, "Invalid event direction %s.  Must be 'assert' or 'deassert'", evdir);
262 		return -1;
263 	}
264 
265 	printf("Finding sensor %s... ", id);
266 	sdr = ipmi_sdr_find_sdr_byid(intf, id);
267 	if (sdr == NULL) {
268 		printf("not found!\n");
269 		return -1;
270 	}
271 	printf("ok\n");
272 
273 	switch (sdr->type)
274 	{
275 	case SDR_RECORD_TYPE_FULL_SENSOR:
276 	case SDR_RECORD_TYPE_COMPACT_SENSOR:
277 
278 		emsg.sensor_type   = sdr->record.common->sensor.type;
279 		emsg.sensor_num    = sdr->record.common->keys.sensor_num;
280 		emsg.event_type    = sdr->record.common->event_type;
281 		target    = sdr->record.common->keys.owner_id;
282 		lun    = sdr->record.common->keys.lun;
283 		channel = sdr->record.common->keys.channel;
284 		break;
285 	default:
286 		lprintf(LOG_ERR, "Unknown sensor type for id '%s'", id);
287 		return -1;
288 	}
289 
290 	emsg.event_data[1] = 0xff;
291 	emsg.event_data[2] = 0xff;
292 
293 	switch (emsg.event_type)
294 	{
295 	/*
296 	 * Threshold Class
297 	 */
298 	case 1:
299 	{
300 		int dir = 0;
301 		int hilo = 0;
302 		off = 1;
303 
304 		if (state == NULL || strncasecmp(state, "list", 4) == 0) {
305 			printf("Sensor States:\n");
306 			printf("  lnr : Lower Non-Recoverable \n");
307 			printf("  lcr : Lower Critical\n");
308 			printf("  lnc : Lower Non-Critical\n");
309 			printf("  unc : Upper Non-Critical\n");
310 			printf("  ucr : Upper Critical\n");
311 			printf("  unr : Upper Non-Recoverable\n");
312 			return -1;
313 		}
314 
315 		if (0 != strncasecmp(state, "lnr", 3) &&
316 		    0 != strncasecmp(state, "lcr", 3) &&
317 		    0 != strncasecmp(state, "lnc", 3) &&
318 		    0 != strncasecmp(state, "unc", 3) &&
319 		    0 != strncasecmp(state, "ucr", 3) &&
320 		    0 != strncasecmp(state, "unr", 3))
321 		{
322 			lprintf(LOG_ERR, "Invalid threshold identifier %s", state);
323 			return -1;
324 		}
325 
326 		if (state[0] == 'u')
327 			hilo = 1;
328 		else
329 			hilo = 0;
330 
331 		if (emsg.event_dir == EVENT_DIR_ASSERT)
332 			dir = hilo;
333 		else
334 			dir = !hilo;
335 
336 		if ((emsg.event_dir == EVENT_DIR_ASSERT   && hilo == 1) ||
337 		    (emsg.event_dir == EVENT_DIR_DEASSERT && hilo == 0))
338 			emsg.event_data[0] = (uint8_t)(str2val(state, ipmi_event_thresh_hi) & 0xf);
339 		else if ((emsg.event_dir == EVENT_DIR_ASSERT   && hilo == 0) ||
340 			 (emsg.event_dir == EVENT_DIR_DEASSERT && hilo == 1))
341 			emsg.event_data[0] = (uint8_t)(str2val(state, ipmi_event_thresh_lo) & 0xf);
342 		else {
343 			lprintf(LOG_ERR, "Invalid Event");
344 			return -1;
345 		}
346 
347 		rsp = ipmi_sdr_get_sensor_thresholds(intf, emsg.sensor_num,
348 							target, lun, channel);
349 		if (rsp == NULL) {
350 			lprintf(LOG_ERR,
351 					"Command Get Sensor Thresholds failed: invalid response.");
352 			return (-1);
353 		} else if (rsp->ccode != 0) {
354 			lprintf(LOG_ERR, "Command Get Sensor Thresholds failed: %s",
355 					val2str(rsp->ccode, completion_code_vals));
356 			return (-1);
357 		}
358 
359 		/* threshold reading */
360 		emsg.event_data[2] = rsp->data[(emsg.event_data[0] / 2) + 1];
361 
362 		rsp = ipmi_sdr_get_sensor_hysteresis(intf, emsg.sensor_num,
363 							target, lun, channel);
364 		if (rsp != NULL && rsp->ccode == 0)
365 			off = dir ? rsp->data[0] : rsp->data[1];
366 		if (off <= 0)
367 			off = 1;
368 
369 		/* trigger reading */
370 		if (dir) {
371 			if ((emsg.event_data[2] + off) > 0xff)
372 				emsg.event_data[1] = 0xff;
373 			else
374 				emsg.event_data[1] = emsg.event_data[2] + off;
375 		}
376 		else {
377 			if ((emsg.event_data[2] - off) < 0)
378 				emsg.event_data[1] = 0;
379 			else
380 				emsg.event_data[1] = emsg.event_data[2] - off;
381 		}
382 
383 		/* trigger in byte 2, threshold in byte 3 */
384 		emsg.event_data[0] |= 0x50;
385 	}
386 	break;
387 
388 	/*
389 	 * Digital Discrete
390 	 */
391 	case 3: case 4: case 5: case 6: case 8: case 9:
392 	{
393 		int x;
394 		const char * digi_on[] = { "present", "assert", "limit",
395 					   "fail", "yes", "on", "up" };
396 		const char * digi_off[] = { "absent", "deassert", "nolimit",
397 					    "nofail", "no", "off", "down" };
398 		/*
399 		 * print list of available states for this sensor
400 		 */
401 		if (state == NULL || strncasecmp(state, "list", 4) == 0) {
402 			print_sensor_states(emsg.sensor_type, emsg.event_type);
403 			printf("Sensor State Shortcuts:\n");
404 			for (x = 0; x < sizeof(digi_on)/sizeof(*digi_on); x++) {
405 				printf("  %-9s  %-9s\n", digi_on[x], digi_off[x]);
406 			}
407 			return 0;
408 		}
409 
410 		off = 0;
411 		for (x = 0; x < sizeof(digi_on)/sizeof(*digi_on); x++) {
412 			if (strncasecmp(state, digi_on[x], strlen(digi_on[x])) == 0) {
413 				emsg.event_data[0] = 1;
414 				off = 1;
415 				break;
416 			}
417 			else if (strncasecmp(state, digi_off[x], strlen(digi_off[x])) == 0) {
418 				emsg.event_data[0] = 0;
419 				off = 1;
420 				break;
421 			}
422 		}
423 		if (off == 0) {
424 			off = ipmi_event_find_offset(
425 				emsg.event_type, generic_event_types, state);
426 			if (off < 0)
427 				return -1;
428 			emsg.event_data[0] = off;
429 		}
430 	}
431 	break;
432 
433 	/*
434 	 * Generic Discrete
435 	 */
436 	case 2: case 7: case 10: case 11: case 12:
437 	{
438 		/*
439 		 * print list of available states for this sensor
440 		 */
441 		if (state == NULL || strncasecmp(state, "list", 4) == 0) {
442 			print_sensor_states(emsg.sensor_type, emsg.event_type);
443 			return 0;
444 		}
445 		off = ipmi_event_find_offset(
446 			emsg.event_type, generic_event_types, state);
447 		if (off < 0)
448 			return -1;
449 		emsg.event_data[0] = off;
450 	}
451 	break;
452 
453 	/*
454 	 * Sensor-Specific Discrete
455 	 */
456 	case 0x6f:
457 	{
458 		/*
459 		 * print list of available states for this sensor
460 		 */
461 		if (state == NULL || strncasecmp(state, "list", 4) == 0) {
462 			print_sensor_states(emsg.sensor_type, emsg.event_type);
463 			return 0;
464 		}
465 		off = ipmi_event_find_offset(
466 			emsg.sensor_type, sensor_specific_types, state);
467 		if (off < 0)
468 			return -1;
469 		emsg.event_data[0] = off;
470 	}
471 	break;
472 
473 	default:
474 		return -1;
475 
476 	}
477 
478 	return ipmi_send_platform_event(intf, &emsg);
479 }
480 
481 static int
ipmi_event_fromfile(struct ipmi_intf * intf,char * file)482 ipmi_event_fromfile(struct ipmi_intf * intf, char * file)
483 {
484 	FILE * fp;
485 	struct ipmi_rs * rsp;
486 	struct ipmi_rq req;
487 	struct sel_event_record sel_event;
488 	uint8_t rqdata[8];
489 	char buf[1024];
490 	char * ptr, * tok;
491 	int i, j;
492 	uint8_t chmed;
493 	int rc = 0;
494 
495 	if (file == NULL)
496 		return -1;
497 
498 	memset(rqdata, 0, 8);
499 
500 	/* setup Platform Event Message command */
501 	memset(&req, 0, sizeof(req));
502 	req.msg.netfn = IPMI_NETFN_SE;
503 	req.msg.cmd = 0x02;
504 	req.msg.data = rqdata;
505 	req.msg.data_len = 7;
506 
507 	chmed = ipmi_current_channel_medium(intf);
508 	if (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM) {
509 		/* system interface, need extra generator ID */
510 		rqdata[0] = 0x41;   // As per Fig. 29-2 and Table 5-4
511 		req.msg.data_len = 8;
512 	}
513 
514 	fp = ipmi_open_file_read(file);
515 	if (fp == NULL)
516 		return -1;
517 
518 	while (feof(fp) == 0) {
519 		if (fgets(buf, 1024, fp) == NULL)
520 			continue;
521 
522 		/* clip off optional comment tail indicated by # */
523 		ptr = strchr(buf, '#');
524 		if (ptr)
525 			*ptr = '\0';
526 		else
527 			ptr = buf + strlen(buf);
528 
529 		/* clip off trailing and leading whitespace */
530 		ptr--;
531 		while (isspace((int)*ptr) && ptr >= buf)
532 			*ptr-- = '\0';
533 		ptr = buf;
534 		while (isspace((int)*ptr))
535 			ptr++;
536 		if (strlen(ptr) == 0)
537 			continue;
538 
539 		/* parse the event, 7 bytes with optional comment */
540 		/* 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # event */
541 		i = 0;
542 		tok = strtok(ptr, " ");
543 		while (tok) {
544 			if (i == 7)
545 				break;
546 			j = i++;
547 			if (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM)
548 				j++;
549 			rqdata[j] = (uint8_t)strtol(tok, NULL, 0);
550 			tok = strtok(NULL, " ");
551 		}
552 		if (i < 7) {
553 			lprintf(LOG_ERR, "Invalid Event: %s",
554 			       buf2str(rqdata, sizeof(rqdata)));
555 			continue;
556 		}
557 
558 		memset(&sel_event, 0, sizeof(struct sel_event_record));
559 		sel_event.record_id = 0;
560 		sel_event.sel_type.standard_type.gen_id = 2;
561 
562 		j = (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM) ? 1 : 0;
563 		sel_event.sel_type.standard_type.evm_rev = rqdata[j++];
564 		sel_event.sel_type.standard_type.sensor_type = rqdata[j++];
565 		sel_event.sel_type.standard_type.sensor_num = rqdata[j++];
566 		sel_event.sel_type.standard_type.event_type = rqdata[j] & 0x7f;
567 		sel_event.sel_type.standard_type.event_dir = (rqdata[j++] & 0x80) >> 7;
568 		sel_event.sel_type.standard_type.event_data[0] = rqdata[j++];
569 		sel_event.sel_type.standard_type.event_data[1] = rqdata[j++];
570 		sel_event.sel_type.standard_type.event_data[2] = rqdata[j++];
571 
572 		ipmi_sel_print_std_entry(intf, &sel_event);
573 
574 		rsp = intf->sendrecv(intf, &req);
575 		if (rsp == NULL) {
576 			lprintf(LOG_ERR, "Platform Event Message command failed");
577 			rc = -1;
578 		}
579 		else if (rsp->ccode > 0) {
580 			lprintf(LOG_ERR, "Platform Event Message command failed: %s",
581 				val2str(rsp->ccode, completion_code_vals));
582 			rc = -1;
583 		}
584 	}
585 
586 	fclose(fp);
587 	return rc;
588 }
589 
590 static void
ipmi_event_usage(void)591 ipmi_event_usage(void)
592 {
593 	lprintf(LOG_NOTICE, "");
594 	lprintf(LOG_NOTICE, "usage: event <num>");
595 	lprintf(LOG_NOTICE, "   Send generic test events");
596 	lprintf(LOG_NOTICE, "   1 : Temperature - Upper Critical - Going High");
597 	lprintf(LOG_NOTICE, "   2 : Voltage Threshold - Lower Critical - Going Low");
598 	lprintf(LOG_NOTICE, "   3 : Memory - Correctable ECC");
599 	lprintf(LOG_NOTICE, "");
600 	lprintf(LOG_NOTICE, "usage: event file <filename>");
601 	lprintf(LOG_NOTICE, "   Read and generate events from file");
602 	lprintf(LOG_NOTICE, "   Use the 'sel save' command to generate from SEL");
603 	lprintf(LOG_NOTICE, "");
604 	lprintf(LOG_NOTICE, "usage: event <sensorid> <state> [event_dir]");
605 	lprintf(LOG_NOTICE, "   sensorid  : Sensor ID string to use for event data");
606 	lprintf(LOG_NOTICE, "   state     : Sensor state, use 'list' to see possible states for sensor");
607 	lprintf(LOG_NOTICE, "   event_dir : assert, deassert [default=assert]");
608 	lprintf(LOG_NOTICE, "");
609 }
610 
611 int
ipmi_event_main(struct ipmi_intf * intf,int argc,char ** argv)612 ipmi_event_main(struct ipmi_intf * intf, int argc, char ** argv)
613 {
614 	int rc = 0;
615 
616 	if (argc == 0 || strncmp(argv[0], "help", 4) == 0) {
617 		ipmi_event_usage();
618 		return 0;
619 	}
620 	if (strncmp(argv[0], "file", 4) == 0) {
621 		if (argc < 2) {
622 			ipmi_event_usage();
623 			return 0;
624 		}
625 		return ipmi_event_fromfile(intf, argv[1]);
626 	}
627 	if (strlen(argv[0]) == 1) {
628 		switch (argv[0][0]) {
629 		case '1': return ipmi_send_platform_event_num(intf, 1);
630 		case '2': return ipmi_send_platform_event_num(intf, 2);
631 		case '3': return ipmi_send_platform_event_num(intf, 3);
632 		}
633 	}
634 	if (argc < 2)
635 		rc = ipmi_event_fromsensor(intf, argv[0], NULL, NULL);
636 	else if (argc < 3)
637 		rc = ipmi_event_fromsensor(intf, argv[0], argv[1], NULL);
638 	else
639 		rc = ipmi_event_fromsensor(intf, argv[0], argv[1], argv[2]);
640 
641 	return rc;
642 }
643