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