/* * 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)); }