/*
* Copyright (C) 2011-2015 FreeIPMI Core Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include
#include
#if STDC_HEADERS
#include
#endif /* STDC_HEADERS */
#if HAVE_UNISTD_H
#include
#endif /* HAVE_UNISTD_H */
#if TIME_WITH_SYS_TIME
#include
#include
#else /* !TIME_WITH_SYS_TIME */
#if HAVE_SYS_TIME_H
#include
#else /* !HAVE_SYS_TIME_H */
#include
#endif /* !HAVE_SYS_TIME_H */
#endif /* !TIME_WITH_SYS_TIME */
#include
#include
#include
#include "ipmi-pet.h"
#include "ipmi-pet-argp.h"
#include "freeipmi-portability.h"
#include "tool-common.h"
#include "tool-cmdline-common.h"
#include "tool-event-common.h"
#include "tool-hostrange-common.h"
#include "tool-oem-common.h"
#include "tool-sdr-cache-common.h"
#include "tool-sensor-common.h"
#include "tool-util-common.h"
#define IPMI_PET_GUID_HEADER "GUID"
#define IPMI_PET_MANUFACTURER_ID_HEADER "Manufacturer ID"
#define IPMI_PET_SYSTEM_ID_HEADER "System ID"
#define IPMI_PET_EVENT_SEVERITY_HEADER "Severity"
struct ipmi_pet_input
{
uint32_t specific_trap;
int specific_trap_na_specified;
uint8_t variable_bindings[IPMI_PLATFORM_EVENT_TRAP_MAX_VARIABLE_BINDINGS_LENGTH];
unsigned int variable_bindings_length;
};
struct ipmi_pet_trap_data
{
uint8_t sensor_type;
int sensor_type_cant_be_determined;
uint8_t event_type;
int event_type_cant_be_determined;
uint8_t event_direction;
uint8_t event_offset;
uint8_t guid[IPMI_SYSTEM_GUID_LENGTH];
uint16_t sequence_number;
uint32_t localtimestamp_raw;
uint32_t localtimestamp;
int16_t utcoffset;
uint8_t event_source_type;
uint8_t event_severity;
uint8_t sensor_device;
uint8_t sensor_number;
uint8_t entity;
uint8_t entity_instance;
uint8_t event_data[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_DATA_LENGTH];
uint8_t language_code;
uint32_t manufacturer_id;
uint16_t system_id;
uint8_t oem_custom[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_OEM_CUSTOM_FIELDS_LENGTH];
unsigned int oem_custom_length;
};
static int
_ipmi_pet_init (ipmi_pet_state_data_t *state_data)
{
struct ipmi_pet_arguments *args;
int rv = -1;
assert (state_data);
args = state_data->prog_data->args;
if (!args->common_args.ignore_sdr_cache)
{
if (calculate_column_widths (NULL,
state_data->sdr_ctx,
NULL,
0,
NULL,
0,
state_data->prog_data->args->non_abbreviated_units,
(args->entity_sensor_names) ? 1 : 0, /* shared_sensors */
1, /* count_event_only_records */
0, /* count_device_locator_records */
0, /* count_oem_records */
args->entity_sensor_names,
&(state_data->column_width)) < 0)
goto cleanup;
}
else
{
if (calculate_column_widths_ignored_sdr_cache (state_data->prog_data->args->non_abbreviated_units,
&(state_data->column_width)) < 0)
goto cleanup;
}
if (args->interpret_oem_data
&& !args->common_args.ignore_sdr_cache)
{
if (ipmi_get_oem_data (NULL,
state_data->ipmi_ctx,
&state_data->oem_data) < 0)
goto cleanup;
}
rv = 0;
cleanup:
return (rv);
}
static int
_ipmi_pet_oem_setup (ipmi_pet_state_data_t *state_data, struct ipmi_pet_trap_data *data)
{
struct ipmi_pet_arguments *args;
int rv = -1;
assert (state_data);
assert (data);
args = state_data->prog_data->args;
if (args->interpret_oem_data)
{
uint32_t manufacturer_id;
uint16_t product_id;
/* Three ways to get manufacturer-id/product-id (in order of preference).
*
* 1) User input - takes highest priority
*
* 2) Trap data - takes priority over IPMI connection because
* maybe running on alternate machine. But only use/assume if
* manufacturer_id/product_id looks ok.
*
* 3) IPMI connection
*/
if (args->manufacturer_id_set
&& args->product_id_set)
{
manufacturer_id = args->manufacturer_id;
product_id = args->product_id;
}
else
{
/* achu: I assume vendors that don't support will likely
* fill in manufacturer_id with something bogus
*/
if (IPMI_IANA_ENTERPRISE_ID_RECOGNIZED (data->manufacturer_id))
{
manufacturer_id = data->manufacturer_id;
product_id = data->system_id;
}
else if (!args->common_args.ignore_sdr_cache)
{
manufacturer_id = state_data->oem_data.manufacturer_id;
product_id = state_data->oem_data.product_id;
}
else
{
/* Eventually will lead to output of number for
* manufacturer id instead of string
*/
manufacturer_id = data->manufacturer_id;
product_id = data->system_id;
}
}
if (ipmi_sel_ctx_set_manufacturer_id (state_data->sel_ctx,
manufacturer_id) < 0)
{
fprintf (stderr,
"ipmi_sel_ctx_set_manufacturer_id: %s\n",
ipmi_sel_ctx_errormsg (state_data->sel_ctx));
goto cleanup;
}
if (ipmi_sel_ctx_set_product_id (state_data->sel_ctx,
product_id) < 0)
{
fprintf (stderr,
"ipmi_sel_ctx_set_product_id: %s\n",
ipmi_sel_ctx_errormsg (state_data->sel_ctx));
goto cleanup;
}
if (args->output_event_state)
{
if (ipmi_interpret_ctx_set_manufacturer_id (state_data->interpret_ctx,
manufacturer_id) < 0)
{
fprintf (stderr,
"ipmi_interpret_ctx_set_manufacturer_id: %s\n",
ipmi_interpret_ctx_errormsg (state_data->interpret_ctx));
goto cleanup;
}
if (ipmi_interpret_ctx_set_product_id (state_data->interpret_ctx,
product_id) < 0)
{
fprintf (stderr,
"ipmi_interpret_ctx_set_product_id: %s\n",
ipmi_interpret_ctx_errormsg (state_data->interpret_ctx));
goto cleanup;
}
}
}
rv = 0;
cleanup:
return (rv);
}
static int
_ipmi_pet_parse_trap_data (ipmi_pet_state_data_t *state_data,
struct ipmi_pet_input *input,
struct ipmi_pet_trap_data *data)
{
int rv = -1;
int i;
assert (state_data);
assert (input);
assert (data);
if (!input->specific_trap_na_specified)
{
uint32_t value;
value = input->specific_trap & IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_SENSOR_TYPE_MASK;
value >>= IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_SENSOR_TYPE_SHIFT;
data->sensor_type = value;
value = input->specific_trap & IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_EVENT_TYPE_MASK;
value >>= IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_EVENT_TYPE_SHIFT;
data->event_type = value;
value = input->specific_trap & IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_EVENT_DIRECTION_MASK;
value >>= IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_EVENT_DIRECTION_SHIFT;
data->event_direction = value;
value = input->specific_trap & IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_EVENT_OFFSET_MASK;
value >>= IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_EVENT_OFFSET_SHIFT;
data->event_offset = value;
}
for (i = 0; i < IPMI_SYSTEM_GUID_LENGTH; i++)
data->guid[i] = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_GUID_INDEX_START + i];
data->sequence_number = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_SEQUENCE_NUMBER_INDEX_START];
data->sequence_number <<= 8;
data->sequence_number |= input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_SEQUENCE_NUMBER_INDEX_START + 1];
data->localtimestamp_raw = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_LOCAL_TIMESTAMP_INDEX_START];
data->localtimestamp_raw <<= 8;
data->localtimestamp_raw |= input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_LOCAL_TIMESTAMP_INDEX_START + 1];
data->localtimestamp_raw <<= 8;
data->localtimestamp_raw |= input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_LOCAL_TIMESTAMP_INDEX_START + 2];
data->localtimestamp_raw <<= 8;
data->localtimestamp_raw |= input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_LOCAL_TIMESTAMP_INDEX_START + 3];
data->localtimestamp = data->localtimestamp_raw;
if (data->localtimestamp != IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_LOCAL_TIMESTAMP_UNSPECIFIED)
{
struct tm tm;
time_t t;
data->utcoffset = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_UTC_OFFSET_INDEX_START];
data->utcoffset <<= 8;
data->utcoffset |= input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_UTC_OFFSET_INDEX_START + 1];
/* utcoffset signed & unspecified 0xffff, cast to remove warnings */
if ((uint16_t)data->utcoffset != IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_UTC_OFFSET_UNSPECIFIED)
{
/* utcoffset is in minutes, multiply by 60 to get seconds */
data->localtimestamp += data->utcoffset * 60;
}
/* Posix says individual calls need not clear/set all portions of
* 'struct tm', thus passing 'struct tm' between functions could
* have issues. So we need to memset.
*/
memset (&tm, '\0', sizeof(struct tm));
/* In PET, epoch is 0:00 hrs 1/1/98
*
* So convert into ansi epoch
*/
tm.tm_year = 98; /* years since 1900 */
tm.tm_mon = 0; /* months since January */
tm.tm_mday = 1; /* 1-31 */
tm.tm_hour = 0;
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_isdst = -1;
if ((t = mktime (&tm)) == (time_t)-1)
{
fprintf (stderr, "Invalid timestamp indicated\n");
goto cleanup;
}
data->localtimestamp += (uint32_t)t;
}
data->event_source_type = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_SOURCE_TYPE_INDEX];
data->event_severity = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_SEVERITY_INDEX];
data->sensor_device = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_SENSOR_DEVICE_INDEX];
data->sensor_number = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_SENSOR_NUMBER_INDEX];
data->entity = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_ENTITY_INDEX];
data->entity_instance = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_ENTITY_INSTANCE_INDEX];
for (i = 0; i < IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_DATA_LENGTH; i++)
data->event_data[i] = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_DATA_INDEX_START + i];
data->language_code = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_LANGUAGE_CODE_INDEX];
data->manufacturer_id = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_MANUFACTURER_ID_INDEX_START];
data->manufacturer_id <<= 8;
data->manufacturer_id |= input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_MANUFACTURER_ID_INDEX_START + 1];
data->manufacturer_id <<= 8;
data->manufacturer_id |= input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_MANUFACTURER_ID_INDEX_START + 2];
data->manufacturer_id <<= 8;
data->manufacturer_id |= input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_MANUFACTURER_ID_INDEX_START + 3];
data->system_id = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_SYSTEM_ID_INDEX_START];
data->system_id <<= 8;
data->system_id |= input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_SYSTEM_ID_INDEX_START + 1];
for (i = 0;
(IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_OEM_CUSTOM_FIELDS_INDEX_START + i) < input->variable_bindings_length;
i++)
{
data->oem_custom[i] = input->variable_bindings[IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_OEM_CUSTOM_FIELDS_INDEX_START + i];
data->oem_custom_length++;
}
rv = 0;
cleanup:
return (rv);
}
static int
_ipmi_pet_form_sel_record (ipmi_pet_state_data_t *state_data,
struct ipmi_pet_trap_data *data,
uint8_t *sel_record,
unsigned int sel_record_len)
{
fiid_obj_t sel_system_event_record = NULL;
int rv = -1;
int len;
assert (state_data);
assert (data);
assert (sel_record);
assert (sel_record_len);
if (!(sel_system_event_record = fiid_obj_create (tmpl_sel_system_event_record)))
{
fprintf (stderr,
"fiid_obj_create: %s\n",
strerror (errno));
goto cleanup;
}
/* Don't care about this field, just set 0 */
if (fiid_obj_set (sel_system_event_record,
"record_id",
0) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'record_id': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"record_type",
IPMI_SEL_RECORD_TYPE_SYSTEM_EVENT_RECORD) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'record_type': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"timestamp",
data->localtimestamp) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'timestamp': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
/* Need just the high order bit here */
if (fiid_obj_set (sel_system_event_record,
"generator_id.id_type",
(data->sensor_device >> 7)) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'generator_id.id_type': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"generator_id.id",
data->sensor_device) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'generator_id.id': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
/* Don't care about this field, just set 0 */
if (fiid_obj_set (sel_system_event_record,
"ipmb_device_lun",
0) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'ipmb_device_lun': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
/* Don't care about this field, just set 0 */
if (fiid_obj_set (sel_system_event_record,
"reserved",
0) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'reserved': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
/* Don't care about this field, just set 0 */
if (fiid_obj_set (sel_system_event_record,
"channel_number",
0) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'channel_number': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"event_message_format_version",
IPMI_V1_5_EVENT_MESSAGE_FORMAT) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'event_message_format_version': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"sensor_type",
data->sensor_type_cant_be_determined ? IPMI_SENSOR_TYPE_RESERVED : data->sensor_type) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'sensor_type': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"sensor_number",
data->sensor_number) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'sensor_number': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"event_type_code",
data->event_type_cant_be_determined ? IPMI_EVENT_READING_TYPE_CODE_UNSPECIFIED : data->event_type) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'event_type_code': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"event_dir",
data->event_direction) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'event_dir': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"event_data1",
data->event_data[0]) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'event_data1': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"event_data2",
data->event_data[1]) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'event_data2': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (fiid_obj_set (sel_system_event_record,
"event_data3",
data->event_data[2]) < 0)
{
fprintf (stderr,
"fiid_obj_set: 'event_data3': %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if ((len = fiid_obj_get_all (sel_system_event_record,
sel_record,
sel_record_len)) < 0)
{
fprintf (stderr,
"fiid_obj_get_all: %s\n",
fiid_obj_errormsg (sel_system_event_record));
goto cleanup;
}
if (len != IPMI_SEL_RECORD_MAX_RECORD_LENGTH)
{
fprintf (stderr,
"Invalid length SEL record: %u\n",
sel_record_len);
goto cleanup;
}
rv = 0;
cleanup:
fiid_obj_destroy (sel_system_event_record);
return (rv);
}
static int
_ipmi_pet_output_headers (ipmi_pet_state_data_t *state_data)
{
assert (state_data);
if (!state_data->prog_data->args->no_header_output
&& !state_data->output_headers)
{
if (state_data->prog_data->args->comma_separated_output)
{
if (state_data->prog_data->args->no_sensor_type_output)
printf ("Date,Time,%s",
SENSORS_HEADER_NAME_STR);
else
printf ("Date,Time,%s,%s",
SENSORS_HEADER_NAME_STR,
SENSORS_HEADER_TYPE_STR);
if (state_data->prog_data->args->verbose_count >= 2)
printf (",%s,%s,%s",
IPMI_PET_GUID_HEADER,
IPMI_PET_MANUFACTURER_ID_HEADER,
IPMI_PET_SYSTEM_ID_HEADER);
if (state_data->prog_data->args->output_event_severity
|| state_data->prog_data->args->verbose_count >= 1)
printf (",%s", IPMI_PET_EVENT_SEVERITY_HEADER);
if (state_data->prog_data->args->output_event_state)
printf (",%s", SENSORS_HEADER_STATE_STR);
if (state_data->prog_data->args->verbose_count >= 1)
printf (",Event Direction");
printf (",Event\n");
}
else
{
char fmt[EVENT_FMT_BUFLEN+1];
memset (fmt, '\0', EVENT_FMT_BUFLEN + 1);
if (state_data->prog_data->args->no_sensor_type_output)
{
snprintf (fmt,
EVENT_FMT_BUFLEN,
"Date | Time | %%-%ds",
state_data->column_width.sensor_name);
printf (fmt, SENSORS_HEADER_NAME_STR);
}
else
{
snprintf (fmt,
EVENT_FMT_BUFLEN,
"Date | Time | %%-%ds | %%-%ds",
state_data->column_width.sensor_name,
state_data->column_width.sensor_type);
printf (fmt,
SENSORS_HEADER_NAME_STR,
SENSORS_HEADER_TYPE_STR);
}
if (state_data->prog_data->args->verbose_count >= 2)
printf (" | %-36s | %-25s | %s",
IPMI_PET_GUID_HEADER,
IPMI_PET_MANUFACTURER_ID_HEADER,
IPMI_PET_SYSTEM_ID_HEADER);
if (state_data->prog_data->args->output_event_severity
|| state_data->prog_data->args->verbose_count >= 1)
printf (" | %-25s", IPMI_PET_EVENT_SEVERITY_HEADER);
if (state_data->prog_data->args->output_event_state)
printf (" | %s ", SENSORS_HEADER_STATE_STR);
if (state_data->prog_data->args->verbose_count >= 1)
printf (" | Event Direction ");
printf (" | Event\n");
}
state_data->output_headers++;
}
return (0);
}
/* return (-1), real error */
static int
_sel_parse_err_handle (ipmi_pet_state_data_t *state_data, char *func)
{
assert (state_data);
assert (func);
if (ipmi_sel_ctx_errnum (state_data->sel_ctx) == IPMI_SEL_ERR_INVALID_SEL_ENTRY)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr,
"Invalid PET data input\n");
return (0);
}
fprintf (stderr,
"%s: %s\n",
func,
ipmi_sel_ctx_errormsg (state_data->sel_ctx));
return (-1);
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_date (ipmi_pet_state_data_t *state_data,
uint8_t *sel_record,
unsigned int sel_record_len,
unsigned int flags)
{
char outbuf[EVENT_OUTPUT_BUFLEN+1];
int outbuf_len;
assert (state_data);
assert (sel_record);
assert (sel_record_len);
memset (outbuf, '\0', EVENT_OUTPUT_BUFLEN+1);
if ((outbuf_len = ipmi_sel_parse_read_record_string (state_data->sel_ctx,
"%d",
sel_record,
sel_record_len,
outbuf,
EVENT_OUTPUT_BUFLEN,
flags)) < 0)
{
if (_sel_parse_err_handle (state_data, "ipmi_sel_parse_format_record_string") < 0)
return (-1);
return (0);
}
if (state_data->prog_data->args->comma_separated_output)
{
if (outbuf_len)
printf ("%s", outbuf);
else
printf ("%s", EVENT_NA_STRING);
}
else
{
if (outbuf_len)
printf ("%-11s", outbuf);
else
printf ("%-11s", EVENT_NA_STRING);
}
return (1);
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_not_available_date (ipmi_pet_state_data_t *state_data)
{
assert (state_data);
if (state_data->prog_data->args->comma_separated_output)
printf ("%s", EVENT_NA_STRING);
else
printf ("%-11s", EVENT_NA_STRING);
return (1);
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_time (ipmi_pet_state_data_t *state_data,
uint8_t *sel_record,
unsigned int sel_record_len,
unsigned int flags)
{
assert (state_data);
assert (sel_record);
assert (sel_record_len);
return (event_output_time (NULL,
state_data->sel_ctx,
sel_record,
sel_record_len,
state_data->prog_data->args->comma_separated_output,
state_data->prog_data->args->common_args.debug,
flags));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_not_available_time (ipmi_pet_state_data_t *state_data)
{
assert (state_data);
return (event_output_not_available_time (NULL,
state_data->prog_data->args->comma_separated_output));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_sensor_name (ipmi_pet_state_data_t *state_data,
uint8_t *sel_record,
unsigned int sel_record_len,
unsigned int flags)
{
assert (state_data);
assert (sel_record);
assert (sel_record_len);
return (event_output_sensor_name (NULL,
state_data->sel_ctx,
sel_record,
sel_record_len,
&state_data->column_width,
&state_data->prog_data->args->common_args,
state_data->prog_data->args->comma_separated_output,
flags));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_sensor_type (ipmi_pet_state_data_t *state_data,
uint8_t *sel_record,
unsigned int sel_record_len,
unsigned int flags)
{
assert (state_data);
assert (!state_data->prog_data->args->no_sensor_type_output);
assert (sel_record);
assert (sel_record_len);
return (event_output_sensor_type (NULL,
state_data->sel_ctx,
sel_record,
sel_record_len,
&state_data->column_width,
state_data->prog_data->args->comma_separated_output,
state_data->prog_data->args->common_args.debug,
flags));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_not_available_sensor_type (ipmi_pet_state_data_t *state_data)
{
assert (state_data);
assert (!state_data->prog_data->args->no_sensor_type_output);
return (event_output_not_available_sensor_type (NULL,
&state_data->column_width,
state_data->prog_data->args->comma_separated_output));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_guid_manufacturer_id_system_id (ipmi_pet_state_data_t *state_data,
struct ipmi_pet_trap_data *data)
{
char fmt[EVENT_FMT_BUFLEN + 1];
char outbuf[EVENT_OUTPUT_BUFLEN+1];
int iana_available;
assert (state_data);
assert (data);
assert (state_data->prog_data->args->verbose_count >= 2);
/* Output format for guid from "Wired for Management Specification",
* Appendix 1 "String Representation of UUIDs" in the above
* document. Note that the output is supposed to be output in most
* significant byte order.
*/
memset (fmt, '\0', EVENT_FMT_BUFLEN + 1);
if (state_data->prog_data->args->comma_separated_output)
snprintf (fmt,
EVENT_FMT_BUFLEN,
",%%02x%%02x%%02x%%02x-%%02x%%02x-%%02x%%02x-%%02x%%02x-%%02x%%02x%%02x%%02x%%02x%%02x");
else
snprintf (fmt,
EVENT_FMT_BUFLEN,
" | %%02x%%02x%%02x%%02x-%%02x%%02x-%%02x%%02x-%%02x%%02x-%%02x%%02x%%02x%%02x%%02x%%02x");
printf (fmt,
data->guid[0], /* time low */
data->guid[1],
data->guid[2],
data->guid[3],
data->guid[4], /* time mid */
data->guid[5],
data->guid[6], /* time high and version */
data->guid[7],
data->guid[8], /* clock seq high and reserved - comes before clock seq low */
data->guid[9], /* clock seq low */
data->guid[10], /* node */
data->guid[11],
data->guid[12],
data->guid[13],
data->guid[14],
data->guid[15]);
/* if iana_available == 0 means no string, < 0 means bad manufacturer id
* either way, output just the number
*/
memset (outbuf, '\0', EVENT_OUTPUT_BUFLEN + 1);
iana_available = ipmi_iana_enterprise_numbers_string (data->manufacturer_id,
outbuf,
EVENT_OUTPUT_BUFLEN);
memset (fmt, '\0', EVENT_FMT_BUFLEN + 1);
if (iana_available > 0)
{
if (state_data->prog_data->args->comma_separated_output)
snprintf (fmt,
EVENT_FMT_BUFLEN,
",%%s,%%u");
else
snprintf (fmt,
EVENT_FMT_BUFLEN,
" | %%-25s | %%-9u");
printf (fmt, outbuf, data->system_id);
}
else
{
if (state_data->prog_data->args->comma_separated_output)
snprintf (fmt,
EVENT_FMT_BUFLEN,
",%%u,%%u");
else
snprintf (fmt,
EVENT_FMT_BUFLEN,
" | %%-25u | %%-9u");
printf (fmt, data->manufacturer_id, data->system_id);
}
return (1);
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_event_severity (ipmi_pet_state_data_t *state_data,
uint8_t event_severity,
unsigned int flags)
{
char *str = NULL;
assert (state_data);
assert (state_data->prog_data->args->output_event_severity
|| state_data->prog_data->args->verbose_count >= 1);
switch (event_severity)
{
case IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_SEVERITY_UNSPECIFIED:
str = EVENT_NA_STRING;
break;
case IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_SEVERITY_MONITOR:
str = "Monitor";
break;
case IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_SEVERITY_INFORMATION:
str = "Information";
break;
case IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_SEVERITY_OK:
str = "Ok";
break;
case IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_SEVERITY_NON_CRITICAL_CONDITION:
str = "Non-critical condition";
break;
case IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_SEVERITY_CRITICAL_CONDITION:
str = "Critical condition";
break;
case IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_EVENT_SEVERITY_NON_RECOVERABLE_CONDITION:
str = "Non-recoverable condition";
break;
default:
str = "Unspecified";
break;
}
if (state_data->prog_data->args->comma_separated_output)
printf (",%s", str);
else
printf (" | %-25s", str);
return (1);
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_event_state (ipmi_pet_state_data_t *state_data,
uint8_t *sel_record,
unsigned int sel_record_len,
unsigned int flags)
{
assert (state_data);
assert (sel_record);
assert (sel_record_len);
assert (state_data->prog_data->args->output_event_state);
return (event_output_event_state (NULL,
state_data->sel_ctx,
sel_record,
sel_record_len,
state_data->prog_data->args->comma_separated_output,
state_data->prog_data->args->common_args.debug,
flags));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_event_direction (ipmi_pet_state_data_t *state_data,
uint8_t *sel_record,
unsigned int sel_record_len,
unsigned int flags)
{
assert (state_data);
assert (sel_record);
assert (sel_record_len);
assert (state_data->prog_data->args->verbose_count >= 1);
return (event_output_event_direction (NULL,
state_data->sel_ctx,
sel_record,
sel_record_len,
state_data->prog_data->args->comma_separated_output,
state_data->prog_data->args->common_args.debug,
flags));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_not_available_event_direction (ipmi_pet_state_data_t *state_data)
{
assert (state_data);
assert (state_data->prog_data->args->verbose_count >= 1);
return (event_output_not_available_event_direction (NULL,
state_data->prog_data->args->comma_separated_output));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_event (ipmi_pet_state_data_t *state_data,
uint8_t *sel_record,
unsigned int sel_record_len,
unsigned int flags,
struct ipmi_pet_trap_data *data)
{
assert (state_data);
assert (sel_record);
assert (sel_record_len);
assert (data);
return (event_output_event (NULL,
state_data->sel_ctx,
sel_record,
sel_record_len,
state_data->prog_data->args->comma_separated_output,
state_data->prog_data->args->common_args.debug,
flags));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_not_available_event (ipmi_pet_state_data_t *state_data)
{
assert (state_data);
return (event_output_not_available_event (NULL,
state_data->prog_data->args->comma_separated_output));
}
/* return 1 on success
* return (0) on non-success, but don't fail
* return (-1) on error
*/
static int
_output_oem_custom (ipmi_pet_state_data_t *state_data,
struct ipmi_pet_trap_data *data)
{
char outbuf[EVENT_OUTPUT_BUFLEN+1];
unsigned int outbuflen = 0;
unsigned int index = 0;
int rv = -1;
assert (state_data);
assert (data);
assert (state_data->prog_data->args->verbose_count >= 1);
memset (outbuf, '\0', EVENT_OUTPUT_BUFLEN + 1);
while (index < data->oem_custom_length
&& data->oem_custom[index] != IPMI_FRU_SENTINEL_VALUE)
{
char tmpbuf[EVENT_OUTPUT_BUFLEN+1];
unsigned int tmpbuflen = EVENT_OUTPUT_BUFLEN;
uint8_t type_length;
uint8_t type_code;
uint8_t number_of_data_bytes;
memset (tmpbuf, '\0', EVENT_OUTPUT_BUFLEN + 1);
type_length = data->oem_custom[index];
type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
number_of_data_bytes = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
/* Special Case: This shouldn't be a length of 0x01 (see type/length
* byte format in FRU Information Storage Definition).
*/
if (type_code == IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE
&& number_of_data_bytes == 0x01)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr,
"Invalid OEM custom data: length invalid\n");
break;
}
if ((index + 1 + number_of_data_bytes) > data->oem_custom_length)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr,
"Invalid OEM custom data: length exceeds input\n");
break;
}
if (ipmi_fru_type_length_field_to_string (state_data->fru_ctx,
&data->oem_custom[index],
number_of_data_bytes + 1,
data->language_code,
tmpbuf,
&tmpbuflen) < 0)
{
if (ipmi_fru_ctx_errnum (state_data->fru_ctx) == IPMI_FRU_ERR_FRU_INFORMATION_INCONSISTENT
|| ipmi_fru_ctx_errnum (state_data->fru_ctx) == IPMI_FRU_ERR_FRU_LANGUAGE_CODE_NOT_SUPPORTED
|| ipmi_fru_ctx_errnum (state_data->fru_ctx) == IPMI_FRU_ERR_FRU_INVALID_BCD_ENCODING)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr,
"Invalid OEM Custom Field: %s\n",
ipmi_fru_ctx_errormsg (state_data->fru_ctx));
break;
}
fprintf (stderr,
"ipmi_fru_type_length_field_to_string: %s\n",
ipmi_fru_ctx_errormsg (state_data->fru_ctx));
goto cleanup;
}
if (tmpbuflen)
{
if (outbuflen)
{
if ((outbuflen + 3) > EVENT_OUTPUT_BUFLEN)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr, "OEM Custom Overflow\n");
break;
}
strcat (outbuf, " ; ");
outbuflen += 3;
}
if ((outbuflen + tmpbuflen) > EVENT_OUTPUT_BUFLEN)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr, "OEM Custom Overflow\n");
break;
}
strcat (outbuf, tmpbuf);
outbuflen += tmpbuflen;
}
index += 1; /* type/length byte */
index += number_of_data_bytes;
}
if (outbuflen)
printf (" ; %s", outbuf);
rv = 1;
cleanup:
return (rv);
}
static int
_ipmi_pet_process (ipmi_pet_state_data_t *state_data,
struct ipmi_pet_input *input)
{
struct ipmi_pet_arguments *args;
struct ipmi_pet_trap_data data;
fiid_obj_t sel_system_event_record_event_fields = NULL;
uint8_t event_offset_test;
uint8_t sel_record[IPMI_SEL_RECORD_MAX_RECORD_LENGTH];
unsigned int flags = 0;
uint64_t val;
int sel_record_len;
int ret;
int rv = -1;
assert (state_data);
assert (input);
memset (&data, '\0', sizeof (struct ipmi_pet_trap_data));
args = state_data->prog_data->args;
if (_ipmi_pet_parse_trap_data (state_data, input, &data) < 0)
goto cleanup;
/* call after parse trap data */
if (_ipmi_pet_oem_setup (state_data, &data) < 0)
goto cleanup;
if (input->specific_trap_na_specified)
{
if (!args->common_args.ignore_sdr_cache)
{
uint8_t record_type;
if (ipmi_sdr_cache_search_sensor_wrapper (state_data->sdr_ctx,
data.sensor_number,
data.sensor_device) < 0)
{
if (ipmi_sdr_ctx_errnum (state_data->sdr_ctx) != IPMI_SDR_ERR_NOT_FOUND)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr,
"ipmi_sdr_cache_search_record_id: %s\n",
ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
goto cleanup;
}
else
goto cant_be_determined;
}
if (ipmi_sdr_parse_record_id_and_type (state_data->sdr_ctx,
NULL,
0,
NULL,
&record_type) < 0)
{
fprintf (stderr,
"ipmi_sdr_parse_record_id_and_type: %s\n",
ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
goto cleanup;
}
if (record_type != IPMI_SDR_FORMAT_FULL_SENSOR_RECORD
&& record_type != IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
&& record_type != IPMI_SDR_FORMAT_EVENT_ONLY_RECORD)
goto cant_be_determined;
if (ipmi_sdr_parse_sensor_type (state_data->sdr_ctx,
NULL,
0,
&data.sensor_type) < 0)
{
fprintf (stderr,
"ipmi_sdr_parse_sensor_type: %s\n",
ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
goto cleanup;
}
if (ipmi_sdr_parse_event_reading_type_code (state_data->sdr_ctx,
NULL,
0,
&data.event_type) < 0)
{
fprintf (stderr,
"ipmi_sdr_parse_event_reading_type_code: %s\n",
ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
goto cleanup;
}
}
else
{
cant_be_determined:
/* Can't determine this stuff */
data.event_type_cant_be_determined = 1;
data.sensor_type_cant_be_determined = 1;
}
}
/* To get very consistent output to ipmi-sel, we will actually stuff
* the above data into a SEL system event, and use that for
* outputting information.
*/
if (_ipmi_pet_form_sel_record (state_data,
&data,
sel_record,
IPMI_SEL_RECORD_MAX_RECORD_LENGTH) < 0)
goto cleanup;
if (input->specific_trap_na_specified
|| data.event_offset != IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_EVENT_OFFSET_UNSPECIFIED)
{
if (!(sel_system_event_record_event_fields = fiid_obj_create (tmpl_sel_system_event_record_event_fields)))
{
fprintf (stderr,
"fiid_obj_create: %s\n",
strerror (errno));
goto cleanup;
}
if ((sel_record_len = fiid_obj_set_all (sel_system_event_record_event_fields,
sel_record,
IPMI_SEL_RECORD_MAX_RECORD_LENGTH)) < 0)
{
fprintf (stderr,
"fiid_obj_set_all: %s\n",
fiid_obj_errormsg (sel_system_event_record_event_fields));
goto cleanup;
}
if (FIID_OBJ_GET (sel_system_event_record_event_fields,
"offset_from_event_reading_type_code",
&val) < 0)
{
fprintf (stderr,
"fiid_obj_get: 'offset_from_event_reading_type_code': %s\n",
fiid_obj_errormsg (sel_system_event_record_event_fields));
goto cleanup;
}
event_offset_test = val;
/* determine event_offset from event data1 */
if (input->specific_trap_na_specified)
data.event_offset = event_offset_test;
else
{
/* If the event offset specified in the specific trap does not
* match the event_data1 data, not much I can really do, one of them is valid and one isn't.
* For now, just document bug.
*/
if (data.event_offset != event_offset_test)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr,
"Invalid PET data input: event_offset and event_data1 inconsistent\n");
}
}
}
if (data.entity != IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_ENTITY_UNSPECIFIED
&& !args->common_args.ignore_sdr_cache)
{
uint8_t entity_id, entity_instance;
if (ipmi_sdr_cache_search_sensor (state_data->sdr_ctx,
data.sensor_number,
data.sensor_device) < 0)
{
if (ipmi_sdr_ctx_errnum (state_data->sdr_ctx) != IPMI_SDR_ERR_NOT_FOUND)
{
fprintf (stderr,
"ipmi_sdr_cache_search_record_id: %s\n",
ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
goto cleanup;
}
else
goto cant_do_entity_id_check;
}
if (ipmi_sdr_parse_entity_id_instance_type (state_data->sdr_ctx,
NULL,
0,
&entity_id,
&entity_instance,
NULL) < 0)
{
fprintf (stderr,
"ipmi_sdr_parse_entity_id_instance_type: %s\n",
ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
goto cleanup;
}
if (entity_id != data.entity)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr,
"Invalid PET data input: entity id inconsistent to SDR data\n");
}
if (data.entity_instance != IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_ENTITY_INSTANCE_UNSPECIFIED)
{
if (entity_instance != data.entity_instance)
{
if (state_data->prog_data->args->common_args.debug)
fprintf (stderr,
"Invalid PET data input: entity instance inconsistent to SDR data\n");
}
}
}
cant_do_entity_id_check:
flags = IPMI_SEL_STRING_FLAGS_IGNORE_UNAVAILABLE_FIELD;
flags |= IPMI_SEL_STRING_FLAGS_OUTPUT_NOT_AVAILABLE;
flags |= IPMI_SEL_STRING_FLAGS_DATE_MONTH_STRING;
if (state_data->prog_data->args->verbose_count >= 3)
flags |= IPMI_SEL_STRING_FLAGS_VERBOSE;
if (state_data->prog_data->args->entity_sensor_names)
flags |= IPMI_SEL_STRING_FLAGS_ENTITY_SENSOR_NAMES;
if (state_data->prog_data->args->non_abbreviated_units)
flags |= IPMI_SEL_STRING_FLAGS_NON_ABBREVIATED_UNITS;
if (state_data->prog_data->args->interpret_oem_data)
flags |= IPMI_SEL_STRING_FLAGS_INTERPRET_OEM_DATA;
if (data.localtimestamp != IPMI_PLATFORM_EVENT_TRAP_VARIABLE_BINDINGS_LOCAL_TIMESTAMP_UNSPECIFIED)
{
if ((ret = _output_date (state_data,
sel_record,
IPMI_SEL_RECORD_MAX_RECORD_LENGTH,
flags)) < 0)
goto cleanup;
if (!ret)
goto newline_out;
if ((ret = _output_time (state_data,
sel_record,
IPMI_SEL_RECORD_MAX_RECORD_LENGTH,
flags)) < 0)
goto cleanup;
if (!ret)
goto newline_out;
}
else
{
if ((ret = _output_not_available_date (state_data)) < 0)
goto cleanup;
if (!ret)
goto newline_out;
if ((ret = _output_not_available_time (state_data)) < 0)
goto cleanup;
if (!ret)
goto newline_out;
}
if ((ret = _output_sensor_name (state_data,
sel_record,
IPMI_SEL_RECORD_MAX_RECORD_LENGTH,
flags)) < 0)
goto cleanup;
if (!ret)
goto newline_out;
if (!state_data->prog_data->args->no_sensor_type_output)
{
if (data.sensor_type_cant_be_determined)
{
if ((ret = _output_not_available_sensor_type (state_data)) < 0)
goto cleanup;
}
else
{
if ((ret = _output_sensor_type (state_data,
sel_record,
IPMI_SEL_RECORD_MAX_RECORD_LENGTH,
flags)) < 0)
goto cleanup;
}
if (!ret)
goto newline_out;
}
if (state_data->prog_data->args->verbose_count >= 2)
{
if ((ret = _output_guid_manufacturer_id_system_id (state_data, &data)) < 0)
goto cleanup;
if (!ret)
goto newline_out;
}
if (state_data->prog_data->args->output_event_severity
|| state_data->prog_data->args->verbose_count >= 1)
{
if ((ret = _output_event_severity (state_data,
data.event_severity,
flags)) < 0)
goto cleanup;
if (!ret)
goto newline_out;
}
if (state_data->prog_data->args->output_event_state)
{
if ((ret = _output_event_state (state_data,
sel_record,
IPMI_SEL_RECORD_MAX_RECORD_LENGTH,
flags)) < 0)
goto cleanup;
if (!ret)
goto newline_out;
}
if (state_data->prog_data->args->verbose_count >= 1)
{
if (input->specific_trap_na_specified
&& args->common_args.ignore_sdr_cache)
{
if ((ret = _output_not_available_event_direction (state_data)) < 0)
goto cleanup;
}
else
{
if ((ret = _output_event_direction (state_data,
sel_record,
IPMI_SEL_RECORD_MAX_RECORD_LENGTH,
flags)) < 0)
goto cleanup;
}
if (!ret)
goto newline_out;
}
if (data.event_offset != IPMI_PLATFORM_EVENT_TRAP_SPECIFIC_TRAP_EVENT_OFFSET_UNSPECIFIED)
{
if (data.event_type_cant_be_determined)
{
if ((ret = _output_not_available_event (state_data)) < 0)
goto cleanup;
}
else
{
if ((ret = _output_event (state_data,
sel_record,
IPMI_SEL_RECORD_MAX_RECORD_LENGTH,
flags,
&data)) < 0)
goto cleanup;
}
}
else
{
if ((ret = _output_not_available_event (state_data)) < 0)
goto cleanup;
}
if (!ret)
goto newline_out;
if (state_data->prog_data->args->verbose_count >= 1)
{
if ((ret = _output_oem_custom (state_data, &data)) < 0)
goto cleanup;
if (!ret)
goto newline_out;
}
newline_out:
printf ("\n");
rv = 0;
cleanup:
fiid_obj_destroy (sel_system_event_record_event_fields);
return (rv);
}
/* returns -1 on fatal error, 0 on non-fatal error, 1 on success */
static int
_ipmi_pet_parse (ipmi_pet_state_data_t *state_data,
const char *line,
struct ipmi_pet_input *input,
unsigned int line_count)
{
const char delim[] = " \t\f\v\r\n";
char *str = NULL;
char *ptr = NULL;
char *token = NULL;
int specific_trap_parsed = 0;
int rv = -1;
assert (state_data);
assert (line);
assert (input);
assert (line_count);
if (!(str = (char *) strdup (line)))
{
perror ("strdup");
goto cleanup;
}
ptr = str;
memset (input, '\0', sizeof (struct ipmi_pet_input));
while (1)
{
unsigned int i;
unsigned long uvalue;
long value;
char *endptr = NULL;
token = strsep (&ptr, delim);
if (!token)
break;
if (!strcmp (token, ""))
continue;
if (!specific_trap_parsed)
{
if (!strcasecmp (token, "NA"))
{
input->specific_trap_na_specified = 1;
specific_trap_parsed++;
continue;
}
errno = 0;
uvalue = strtoul (token, &endptr, 0);
if (errno
|| endptr[0] != '\0')
{
fprintf (stderr, "invalid specific trap argument on line %u\n", line_count);
rv = 0;
goto cleanup;
}
input->specific_trap = uvalue;
specific_trap_parsed++;
continue;
}
if (strlen (token) >= 2)
{
if (!strncmp (token, "0x", 2))
token+=2;
}
if (*token == '\0')
{
fprintf (stderr, "invalid variable binding hex byte argument on line %u\n", line_count);
rv = 0;
goto cleanup;
}
for (i = 0; token[i] != '\0'; i++)
{
if (i >= 2)
{
fprintf (stderr, "invalid variable binding hex byte argument on line %u\n", line_count);
rv = 0;
goto cleanup;
}
if (!isxdigit (token[i]))
{
fprintf (stderr, "invalid variable binding hex byte argument on line %u\n", line_count);
rv = 0;
goto cleanup;
}
}
if (input->variable_bindings_length < IPMI_PLATFORM_EVENT_TRAP_MAX_VARIABLE_BINDINGS_LENGTH)
{
errno = 0;
value = strtol (token, &endptr, 16);
if (errno
|| endptr[0] != '\0')
{
fprintf (stderr, "invalid variable binding hex byte argument on line %u\n", line_count);
rv = 0;
goto cleanup;
}
input->variable_bindings[input->variable_bindings_length++] = (uint8_t) value;
}
else
{
fprintf (stderr, "Too many arguments specified on line %u\n", line_count);
rv = 0;
goto cleanup;
}
}
if (!(input->variable_bindings_length >= IPMI_PLATFORM_EVENT_TRAP_MIN_VARIABLE_BINDINGS_LENGTH
&& input->variable_bindings_length <= IPMI_PLATFORM_EVENT_TRAP_MAX_VARIABLE_BINDINGS_LENGTH))
{
fprintf (stderr,
"Invalid number of variable binding bytes on line %u\n",
line_count);
rv = 0;
goto cleanup;
}
rv = 1;
cleanup:
free (str);
return (rv);
}
static int
_ipmi_pet_acknowledge (ipmi_pet_state_data_t *state_data, FILE *stream)
{
struct ipmi_pet_arguments *args;
struct ipmi_pet_input input;
struct ipmi_pet_trap_data data;
uint32_t event_data;
fiid_obj_t obj_cmd_rs = NULL;
char *line = NULL;
unsigned int ctx_flags_orig;
int rv = -1;
assert (state_data);
assert (state_data->ipmi_ctx);
assert (state_data->prog_data->args->pet_acknowledge);
assert ((state_data->prog_data->args->variable_bindings_length && !stream)
|| (!state_data->prog_data->args->variable_bindings_length && stream));
args = state_data->prog_data->args;
if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_pet_acknowledge_rs)))
{
perror ("fiid_obj_create");
goto cleanup;
}
if (args->common_args.section_specific_workaround_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_MALFORMED_ACK)
{
if (ipmi_ctx_get_flags (state_data->ipmi_ctx, &ctx_flags_orig) < 0)
{
fprintf (stderr,
"ipmi_ctx_get_flags: %s\n",
ipmi_ctx_errormsg (state_data->ipmi_ctx));
goto cleanup;
}
if (ipmi_ctx_set_flags (state_data->ipmi_ctx, ctx_flags_orig | IPMI_FLAGS_NO_LEGAL_CHECK) < 0)
{
fprintf (stderr,
"ipmi_ctx_set_flags: %s\n",
ipmi_ctx_errormsg (state_data->ipmi_ctx));
goto cleanup;
}
}
if (args->variable_bindings_length)
{
if (!(args->variable_bindings_length >= IPMI_PLATFORM_EVENT_TRAP_MIN_VARIABLE_BINDINGS_LENGTH
&& args->variable_bindings_length <= IPMI_PLATFORM_EVENT_TRAP_MAX_VARIABLE_BINDINGS_LENGTH))
{
fprintf (stderr,
"Invalid number of variable binding bytes\n");
goto cleanup;
}
input.specific_trap = args->specific_trap;
input.specific_trap_na_specified = args->specific_trap_na_specified;
memcpy (input.variable_bindings,
args->variable_bindings,
args->variable_bindings_length);
input.variable_bindings_length = args->variable_bindings_length;
if (_ipmi_pet_parse_trap_data (state_data,
&input,
&data) < 0)
goto cleanup;
event_data = data.event_data[2];
event_data <<= 8;
event_data |= data.event_data[1];
event_data <<= 8;
event_data |= data.event_data[0];
if (ipmi_cmd_pet_acknowledge (state_data->ipmi_ctx,
data.sequence_number,
data.localtimestamp_raw,
data.event_source_type,
data.sensor_device,
data.sensor_number,
event_data,
obj_cmd_rs) < 0)
{
fprintf (stderr,
"ipmi_cmd_pet_acknowledge: %s\n",
ipmi_ctx_errormsg (state_data->ipmi_ctx));
goto cleanup;
}
}
else
{
size_t n = 0;
unsigned int line_count = 0;
int ret;
while (1)
{
if (getline (&line, &n, stream) < 0)
{
/* perror ("getline()"); */
break;
}
line_count++;
if ((ret = _ipmi_pet_parse (state_data, line, &input, line_count)) < 0)
goto cleanup;
if (!ret)
goto end_loop;
if (_ipmi_pet_parse_trap_data (state_data,
&input,
&data) < 0)
goto cleanup;
event_data = data.event_data[2];
event_data <<= 8;
event_data |= data.event_data[1];
event_data <<= 8;
event_data |= data.event_data[0];
if (ipmi_cmd_pet_acknowledge (state_data->ipmi_ctx,
data.sequence_number,
data.localtimestamp_raw,
data.event_source_type,
data.sensor_device,
data.sensor_number,
event_data,
obj_cmd_rs) < 0)
{
fprintf (stderr,
"ipmi_cmd_pet_acknowledge: %s\n",
ipmi_ctx_errormsg (state_data->ipmi_ctx));
goto cleanup;
}
end_loop:
free (line);
line = NULL;
n = 0;
}
}
if (args->common_args.section_specific_workaround_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_MALFORMED_ACK)
{
if (ipmi_ctx_set_flags (state_data->ipmi_ctx, ctx_flags_orig) < 0)
{
fprintf (stderr,
"ipmi_ctx_set_flags: %s\n",
ipmi_ctx_errormsg (state_data->ipmi_ctx));
goto cleanup;
}
}
rv = 0;
cleanup:
fiid_obj_destroy (obj_cmd_rs);
free (line);
return (rv);
}
static int
_ipmi_pet_cmdline (ipmi_pet_state_data_t *state_data)
{
struct ipmi_pet_arguments *args;
struct ipmi_pet_input input;
int rv = -1;
assert (state_data);
assert (state_data->prog_data->args->specific_trap_set);
assert (state_data->prog_data->args->variable_bindings);
assert (state_data->prog_data->args->variable_bindings_length);
args = state_data->prog_data->args;
if (!(args->variable_bindings_length >= IPMI_PLATFORM_EVENT_TRAP_MIN_VARIABLE_BINDINGS_LENGTH
&& args->variable_bindings_length <= IPMI_PLATFORM_EVENT_TRAP_MAX_VARIABLE_BINDINGS_LENGTH))
{
fprintf (stderr,
"Invalid number of variable binding bytes\n");
goto cleanup;
}
if (_ipmi_pet_init (state_data) < 0)
goto cleanup;
if (_ipmi_pet_output_headers (state_data) < 0)
goto cleanup;
input.specific_trap = args->specific_trap;
input.specific_trap_na_specified = args->specific_trap_na_specified;
memcpy (input.variable_bindings,
args->variable_bindings,
args->variable_bindings_length);
input.variable_bindings_length = args->variable_bindings_length;
if (_ipmi_pet_process (state_data, &input) < 0)
goto cleanup;
rv = 0;
cleanup:
return (rv);
}
static int
_ipmi_pet_stream (ipmi_pet_state_data_t *state_data, FILE *stream)
{
char *line = NULL;
size_t n = 0;
unsigned int line_count = 0;
int rv = -1;
int ret;
assert (state_data);
assert (stream);
if (_ipmi_pet_init (state_data) < 0)
goto cleanup;
while (1)
{
struct ipmi_pet_input input;
if (getline (&line, &n, stream) < 0)
{
/* perror ("getline()"); */
break;
}
line_count++;
/* On invalid inputs, we could exit. However, we assume the
* user is inputting a large stream of traps, possibly after
* parsing it from a log or something. So we just output an
* error and continue on with trap interpretations when there is
* an invalid input.
*/
if ((ret = _ipmi_pet_parse (state_data, line, &input, line_count)) < 0)
goto cleanup;
if (!ret)
goto end_loop;
if (_ipmi_pet_output_headers (state_data) < 0)
goto cleanup;
if (_ipmi_pet_process (state_data, &input) < 0)
goto cleanup;
end_loop:
free (line);
line = NULL;
n = 0;
}
rv = 0;
cleanup:
free (line);
return (rv);
}
static int
run_cmd_args (ipmi_pet_state_data_t *state_data)
{
struct ipmi_pet_arguments *args;
FILE *infile = NULL;
int rv = -1;
assert (state_data);
args = state_data->prog_data->args;
assert (!args->common_args.flush_cache);
if (args->variable_bindings_length)
{
if (args->pet_acknowledge)
{
if (_ipmi_pet_acknowledge (state_data, NULL) < 0)
goto cleanup;
}
else
{
if (_ipmi_pet_cmdline (state_data) < 0)
goto cleanup;
}
return (0);
}
if (args->cmd_file)
{
if (!(infile = fopen (args->cmd_file, "r")))
{
perror ("fopen()");
goto cleanup;
}
}
else
infile = stdin;
if (args->pet_acknowledge)
{
if (_ipmi_pet_acknowledge (state_data, infile) < 0)
goto cleanup;
}
else
{
if (_ipmi_pet_stream (state_data, infile) < 0)
goto cleanup;
}
rv = 0;
cleanup:
if (infile && infile != stdin)
fclose (infile);
return (rv);
}
static int
_ipmi_pet (ipmi_pet_prog_data_t *prog_data)
{
ipmi_pet_state_data_t state_data;
int exit_code = EXIT_FAILURE;
assert (prog_data);
if (prog_data->args->common_args.flush_cache)
{
if (sdr_cache_flush_cache (NULL,
prog_data->args->common_args.hostname,
&prog_data->args->common_args) < 0)
return (EXIT_FAILURE);
return (EXIT_SUCCESS);
}
memset (&state_data, '\0', sizeof (ipmi_pet_state_data_t));
state_data.prog_data = prog_data;
state_data.hostname = prog_data->args->common_args.hostname;
if (!prog_data->args->common_args.ignore_sdr_cache
&& !prog_data->args->pet_acknowledge)
{
if (!(state_data.ipmi_ctx = ipmi_open (prog_data->progname,
prog_data->args->common_args.hostname,
&(prog_data->args->common_args),
NULL,
0)))
goto cleanup;
}
if (prog_data->args->pet_acknowledge)
{
if (!(state_data.ipmi_ctx = ipmi_ctx_create ()))
{
perror ("ipmi_ctx_create()");
goto cleanup;
}
if (ipmi_ctx_open_outofband (state_data.ipmi_ctx,
state_data.hostname,
NULL,
NULL,
IPMI_AUTHENTICATION_TYPE_NONE, /* doesn't matter, just anything legal */
IPMI_PRIVILEGE_LEVEL_USER, /* doesn't matter, just anything legal */
0,
0,
0,
IPMI_FLAGS_NOSESSION | (prog_data->args->common_args.debug ? IPMI_FLAGS_DEBUG_DUMP : IPMI_FLAGS_DEFAULT)) < 0)
{
if (ipmi_ctx_errnum (state_data.ipmi_ctx) == IPMI_ERR_HOSTNAME_INVALID)
fprintf (stderr, "%s: %s\n", prog_data->progname, ipmi_ctx_errormsg (state_data.ipmi_ctx));
else
fprintf (stderr, "ipmi_ctx_open_outofband: %s\n", ipmi_ctx_errormsg (state_data.ipmi_ctx));
goto cleanup;
}
}
if (!prog_data->args->common_args.ignore_sdr_cache
&& !prog_data->args->pet_acknowledge)
{
if (!(state_data.sdr_ctx = ipmi_sdr_ctx_create ()))
{
perror ("ipmi_sdr_ctx_create()");
goto cleanup;
}
if (!prog_data->args->pet_acknowledge)
{
if (sdr_cache_create_and_load (state_data.sdr_ctx,
NULL,
state_data.ipmi_ctx,
state_data.hostname,
&state_data.prog_data->args->common_args) < 0)
goto cleanup;
}
}
else
state_data.sdr_ctx = NULL;
if (!(state_data.sel_ctx = ipmi_sel_ctx_create (NULL, state_data.sdr_ctx)))
{
perror ("ipmi_sel_ctx_create()");
goto cleanup;
}
if (state_data.prog_data->args->common_args.debug
&& prog_data->args->common_args.hostname)
{
if (ipmi_sel_ctx_set_debug_prefix (state_data.sel_ctx,
prog_data->args->common_args.hostname) < 0)
fprintf (stderr,
"ipmi_sel_ctx_set_debug_prefix: %s\n",
ipmi_sel_ctx_errormsg (state_data.sel_ctx));
}
/* Only for outputting type/length fields */
if (!(state_data.fru_ctx = ipmi_fru_ctx_create (NULL)))
{
perror ("ipmi_fru_ctx_create()");
goto cleanup;
}
if (prog_data->args->output_event_state)
{
unsigned int flags = 0;
if (!(state_data.interpret_ctx = ipmi_interpret_ctx_create ()))
{
perror ("ipmi_interpret_ctx_create()");
goto cleanup;
}
if (event_load_event_state_config_file (NULL,
state_data.interpret_ctx,
prog_data->args->event_state_config_file) < 0)
goto cleanup;
if (prog_data->args->interpret_oem_data)
flags |= IPMI_INTERPRET_FLAGS_INTERPRET_OEM_DATA;
if (flags)
{
if (ipmi_interpret_ctx_set_flags (state_data.interpret_ctx, flags) < 0)
{
fprintf (stderr,
"ipmi_interpret_ctx_set_flags: %s\n",
ipmi_interpret_ctx_errormsg (state_data.interpret_ctx));
goto cleanup;
}
}
if (ipmi_sel_ctx_set_parameter (state_data.sel_ctx,
IPMI_SEL_PARAMETER_INTERPRET_CONTEXT,
&(state_data.interpret_ctx)) < 0)
{
fprintf (stderr,
"ipmi_sel_ctx_set_interpret: %s\n",
ipmi_sel_ctx_errormsg (state_data.sel_ctx));
goto cleanup;
}
}
if (run_cmd_args (&state_data) < 0)
goto cleanup;
exit_code = EXIT_SUCCESS;
cleanup:
ipmi_fru_ctx_destroy (state_data.fru_ctx);
ipmi_interpret_ctx_destroy (state_data.interpret_ctx);
ipmi_sel_ctx_destroy (state_data.sel_ctx);
ipmi_sdr_ctx_destroy (state_data.sdr_ctx);
ipmi_ctx_close (state_data.ipmi_ctx);
ipmi_ctx_destroy (state_data.ipmi_ctx);
return (exit_code);
}
int
main (int argc, char **argv)
{
ipmi_pet_prog_data_t prog_data;
struct ipmi_pet_arguments cmd_args;
ipmi_disable_coredump ();
prog_data.progname = argv[0];
ipmi_pet_argp_parse (argc, argv, &cmd_args);
prog_data.args = &cmd_args;
return (_ipmi_pet (&prog_data));
}