static int
_ipmimonitoring_legacy_simple_output_header (ipmi_sensors_state_data_t *state_data,
                                             uint16_t record_id)
{
  char id_string[IPMI_SDR_MAX_ID_STRING_LENGTH + 1];
  uint8_t sensor_type;
  uint8_t event_reading_type_code;
  const char * sensor_type_string = NULL;

  assert (state_data);

  memset (id_string, '\0', IPMI_SDR_MAX_ID_STRING_LENGTH + 1);

  if (ipmi_sdr_parse_id_string (state_data->sdr_ctx,
                                NULL,
                                0,
                                id_string,
                                IPMI_SDR_MAX_ID_STRING_LENGTH) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_id_string: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      return (-1);
    }

  if (ipmi_sdr_parse_sensor_type (state_data->sdr_ctx,
                                  NULL,
                                  0,
                                  &sensor_type) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_sensor_type: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      return (-1);
    }

  if ((state_data->prog_data->args->interpret_oem_data)
      && (ipmi_sdr_parse_event_reading_type_code (state_data->sdr_ctx,
                                                  NULL,
                                                  0,
                                                  &event_reading_type_code) >= 0))
    sensor_type_string = get_oem_sensor_type_output_string (sensor_type,
                                                            event_reading_type_code,
                                                            state_data->oem_data.manufacturer_id,
                                                            state_data->oem_data.product_id);
  else 
    sensor_type_string = get_sensor_type_output_string (sensor_type);
      
  pstdout_printf (state_data->pstate,
                  "%u | %s | %s",
                  record_id,
                  id_string,
                  sensor_type_string);

  return (0);
}
static int
_sections_sdr_callback (ipmi_sdr_ctx_t sdr_ctx,
			uint8_t record_type,
			const void *sdr_record,
			unsigned int sdr_record_len,
			void *arg)
{
  struct ipmi_sensors_config_sdr_callback *sdr_callback_arg;
  ipmi_sensors_config_state_data_t *state_data;
  struct config_section *section = NULL;
  uint8_t event_reading_type_code;
  int event_reading_type_code_class;
  config_err_t ret;

  assert (sdr_ctx);
  assert (sdr_record);
  assert (sdr_record_len);
  assert (arg);

  sdr_callback_arg = (struct ipmi_sensors_config_sdr_callback *)arg;
  state_data = sdr_callback_arg->state_data;

  /* achu:
   *
   * Technically, the IPMI spec lists that compact record formats
   * also support settable thresholds.  However, since compact
   * records don't contain any information for interpreting
   * threshold sensors (e.g. R exponent) I don't know how they
   * could be of any use.  No vendor that I know of supports
   * threshold sensors via a compact record (excluding possible
   * OEM ones).
   *
   * There's a part of me that believes the readable/setting
   * threshold masks for compact sensor records is a cut and paste
   * typo.  It shouldn't be there.
   */
  
  if (record_type != IPMI_SDR_FORMAT_FULL_SENSOR_RECORD
      && record_type != IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD)
    {
      if (state_data->prog_data->args->config_args.verbose_count)
	pstdout_fprintf (state_data->pstate,
			 stderr,
			 "## Cannot handle SDR record format '0x%X'\n",
			 record_type);
      return (0);
    }
  
  if (ipmi_sdr_parse_event_reading_type_code (state_data->sdr_ctx,
					      sdr_record,
					      sdr_record_len,
					      &event_reading_type_code) < 0)
    {
      pstdout_fprintf (state_data->pstate,
		       stderr,
		       "ipmi_sdr_parse_event_reading_type_code: %s\n",
		       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      return (-1);
    }

  event_reading_type_code_class = ipmi_event_reading_type_code_class (event_reading_type_code);

  if (event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_THRESHOLD)
    {
      if (record_type != IPMI_SDR_FORMAT_FULL_SENSOR_RECORD)
	{
	  if (state_data->prog_data->args->config_args.verbose_count)
	    pstdout_printf (state_data->pstate,
			    "## Unable to handle threshold sensor with compact SDR record\n");
	  return (0);
	}

      if ((ret = ipmi_sensors_config_threshold_section (state_data,
							&section)) != CONFIG_ERR_SUCCESS)
	{
	  if (ret == CONFIG_ERR_FATAL_ERROR)
	    return (-1);
	  return (0);
	}
    }
  else if (event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_GENERIC_DISCRETE
	   || event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_SENSOR_SPECIFIC_DISCRETE)
    {
      if ((ret = ipmi_sensors_config_discrete_section (state_data,
						       &section)) != CONFIG_ERR_SUCCESS)
	{
	  if (ret == CONFIG_ERR_FATAL_ERROR)
	    return (-1);
	  return (0);
	}
    }
  else
    {
      if (state_data->prog_data->args->config_args.common_args.debug)
	pstdout_fprintf (state_data->pstate,
			 stderr,
			 "## Cannot handle SDR with event reading type code '0x%X'\n",
			 event_reading_type_code);
      return (0);
    }

  if (config_section_append (&sdr_callback_arg->sections, section) < 0)
    return (-1);

  return (0);
}
Example #3
0
int
ipmi_sensor_read (ipmi_sensor_read_ctx_t ctx,
                  const void *sdr_record,
                  unsigned int sdr_record_len,
                  uint8_t shared_sensor_number_offset,
                  uint8_t *sensor_reading_raw,
                  double **sensor_reading,
                  uint16_t *sensor_event_bitmask)
{
  double *tmp_sensor_reading = NULL;
  uint64_t val;
  int rv = -1;
  fiid_obj_t obj_cmd_rs = NULL;
  uint8_t sensor_event_bitmask1 = 0;
  uint8_t sensor_event_bitmask2 = 0;
  int sensor_event_bitmask1_flag = 0;
  int sensor_event_bitmask2_flag = 0;
  uint16_t record_id = 0;
  uint8_t record_type = 0;
  uint8_t sensor_number = 0;
  uint8_t event_reading_type_code = 0;
  uint8_t sensor_owner_id_type = 0;
  uint8_t sensor_owner_id = 0;
  uint8_t sensor_owner_lun = 0;
  uint8_t channel_number = 0;
  uint8_t slave_address = 0;
  uint8_t reading_state, sensor_scanning;
  uint8_t local_sensor_reading_raw;
  unsigned int ctx_flags_orig;
  int event_reading_type_code_class = 0;

  if (!ctx || ctx->magic != IPMI_SENSOR_READ_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sensor_read_ctx_errormsg (ctx), ipmi_sensor_read_ctx_errnum (ctx));
      return (-1);
    }

  if (!sdr_record
      || !sdr_record_len
      || !sensor_reading
      || !sensor_event_bitmask)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_PARAMETERS);
      return (-1);
    }

  *sensor_reading = NULL;
  *sensor_event_bitmask = 0;

  if (ipmi_sdr_parse_record_id_and_type (ctx->sdr_ctx,
                                         sdr_record,
                                         sdr_record_len,
                                         &record_id,
                                         &record_type) < 0)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR);
      goto cleanup;
    }

  if (record_type != IPMI_SDR_FORMAT_FULL_SENSOR_RECORD
      && record_type != IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INVALID_SDR_RECORD_TYPE);
      goto cleanup;
    }

  if (ipmi_sdr_parse_sensor_owner_id (ctx->sdr_ctx,
                                      sdr_record,
                                      sdr_record_len,
                                      &sensor_owner_id_type,
                                      &sensor_owner_id) < 0)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR);
      goto cleanup;
    }

  if (ipmi_sdr_parse_sensor_owner_lun (ctx->sdr_ctx,
                                       sdr_record,
                                       sdr_record_len,
                                       &sensor_owner_lun,
                                       &channel_number) < 0)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR);
      goto cleanup;
    }

  if (ipmi_sdr_parse_sensor_number (ctx->sdr_ctx,
                                    sdr_record,
                                    sdr_record_len,
                                    &sensor_number) < 0)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR);
      goto cleanup;
    }

  if (shared_sensor_number_offset)
    {
      uint8_t share_count;

      if (record_type != IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD)
        {
          SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INVALID_SDR_RECORD_TYPE);
          goto cleanup;
        }

      if (ipmi_sdr_parse_sensor_record_sharing (ctx->sdr_ctx,
                                                sdr_record,
                                                sdr_record_len,
                                                &share_count,
                                                NULL,
                                                NULL,
                                                NULL) < 0)
        {
          SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR);
          goto cleanup;
        }

      if (share_count <= 1)
        {
          SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INVALID_SDR_RECORD_TYPE);
          goto cleanup;
        }

      if ((sensor_number + share_count) < (sensor_number + shared_sensor_number_offset))
        {
          SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_PARAMETERS);
          goto cleanup;
        }

      sensor_number += shared_sensor_number_offset;
    }

  if (ipmi_sdr_parse_event_reading_type_code (ctx->sdr_ctx,
                                              sdr_record,
                                              sdr_record_len,
                                              &event_reading_type_code) < 0)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR);
      goto cleanup;
    }

  if (sensor_owner_id_type == IPMI_SDR_SENSOR_OWNER_ID_TYPE_SYSTEM_SOFTWARE_ID)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_IS_SYSTEM_SOFTWARE);
      goto cleanup;
    }

  slave_address = (sensor_owner_id << 1) | sensor_owner_id_type;

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_sensor_reading_rs)))
    {
      SENSOR_READ_ERRNO_TO_SENSOR_READ_ERRNUM (ctx, errno);
      goto cleanup;
    }

  /* 
   * IPMI Workaround (achu)
   *
   * See comments below concerning sensor_event_bitmask.
   */

  if (ipmi_ctx_get_flags (ctx->ipmi_ctx, &ctx_flags_orig) < 0)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR);
      goto cleanup;
    }

  if (ipmi_ctx_set_flags (ctx->ipmi_ctx, ctx_flags_orig | IPMI_FLAGS_NO_VALID_CHECK) < 0)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR);
      goto cleanup;
    }

  /* IPMI Workaround
   *
   * Discovered on Fujitsu RX300
   * Discovered on Fujitsu RX300S2
   * 
   * On some motherboards, the sensor owner is invalid.  The sensor
   * owner as atually the BMC.
   */
  if (!(ctx->flags & IPMI_SENSOR_READ_FLAGS_ASSUME_BMC_OWNER))
    {
      if (slave_address == IPMI_SLAVE_ADDRESS_BMC)
        {
          if (_get_sensor_reading (ctx,
                                   sensor_number,
                                   obj_cmd_rs) < 0)
            goto cleanup;
        }
      else
        {
          if (_get_sensor_reading_ipmb (ctx,
                                        slave_address,
                                        sensor_owner_lun,
                                        channel_number,
                                        sensor_number,
                                        obj_cmd_rs) < 0)
            goto cleanup;
        }
    }
  else
    {
      if (_get_sensor_reading (ctx,
                               sensor_number,
                               obj_cmd_rs) < 0)
        goto cleanup;
    }

  /* 
   * IPMI Workaround (achu)
   *
   * See comments below concerning sensor_event_bitmask.
   */

  if (ipmi_ctx_set_flags (ctx->ipmi_ctx, ctx_flags_orig) < 0)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR);
      goto cleanup;
    }

  if (FIID_OBJ_GET (obj_cmd_rs,
                    "reading_state",
                    &val) < 0)
    {
      SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs);
      goto cleanup;
    }
  reading_state = val;

  if (reading_state == IPMI_SENSOR_READING_STATE_UNAVAILABLE)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_READING_UNAVAILABLE);
      goto cleanup;
    }

  /* IPMI Workaround
   *
   * Discovered on Dell Poweredge 2900
   * Discovered on Dell Poweredge 2950
   * Discovered on Dell Poweredge R410
   * Discovered on Dell Poweredge R610
   * 
   * On some motherboards, the sensor scanning bit is invalid for sensors. 
   */
  if (!(ctx->flags & IPMI_SENSOR_READ_FLAGS_IGNORE_SCANNING_DISABLED))
    {
      if (FIID_OBJ_GET (obj_cmd_rs,
                        "sensor_scanning",
                        &val) < 0)
        {
          SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs);
          goto cleanup;
        }
      sensor_scanning = val;
      
      if (sensor_scanning == IPMI_SENSOR_SCANNING_ON_THIS_SENSOR_DISABLE)
        {
          SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_SCANNING_DISABLED);
          goto cleanup;
        }
    }

  /* achu:
   *
   * Note: I don't bother checking the "all_event_messages" flag from
   * the get_sensor_reading response.  If that stuff is turned off,
   * the bitmasks should be zeroed out.
   *
   * Hopefully this doesn't bite me later on.
   *
   * Call the normal fiid_obj_get instead of the wrapper, if the field
   * isn't set, we want to know and not error out.
   */

  if ((sensor_event_bitmask1_flag = fiid_obj_get (obj_cmd_rs,
                                                  "sensor_event_bitmask1",
                                                  &val)) < 0)
    {
      SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs);
      goto cleanup;
    }
  sensor_event_bitmask1 = val;

  if ((sensor_event_bitmask2_flag = fiid_obj_get (obj_cmd_rs,
                                                  "sensor_event_bitmask2",
                                                  &val)) < 0)
    {
      SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs);
      goto cleanup;
    }
  sensor_event_bitmask2 = val;

  /*
   * IPMI Workaround (achu)
   *
   * Discovered on Dell 2950.
   *
   * It seems the sensor_event_bitmask (16 bits) may not be returned
   * by the server at all for some sensors, despite a minimum of 8
   * bits being required.  Under this situation, there's not much that
   * can be done.  Since there is no sensor_event_bitmask, we just
   * assume that no states have been asserted and the
   * sensor_event_bitmask = 0;
   */

  if (!sensor_event_bitmask1_flag && !sensor_event_bitmask2_flag)
    (*sensor_event_bitmask) = 0;
  else if (sensor_event_bitmask1_flag && sensor_event_bitmask2_flag)
    (*sensor_event_bitmask) = sensor_event_bitmask1 | (sensor_event_bitmask2 << 8);
  else if (sensor_event_bitmask1_flag && !sensor_event_bitmask2_flag)
    (*sensor_event_bitmask) = sensor_event_bitmask1;
  else
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_IPMI_ERROR);
      goto cleanup;
    }

  if (FIID_OBJ_GET (obj_cmd_rs,
                    "sensor_reading",
                    &val) < 0)
    {
      SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs);
      goto cleanup;
    }
  local_sensor_reading_raw = val;
  
  if (sensor_reading_raw)
    (*sensor_reading_raw) = local_sensor_reading_raw;

  event_reading_type_code_class = ipmi_event_reading_type_code_class (event_reading_type_code);

  if (event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_THRESHOLD)
    {
      if (record_type == IPMI_SDR_FORMAT_FULL_SENSOR_RECORD)
        {
          int8_t r_exponent, b_exponent;
          int16_t m, b;
          uint8_t linearization, analog_data_format;

          if (ipmi_sdr_parse_sensor_decoding_data (ctx->sdr_ctx,
                                                   sdr_record,
                                                   sdr_record_len,
                                                   &r_exponent,
                                                   &b_exponent,
                                                   &m,
                                                   &b,
                                                   &linearization,
                                                   &analog_data_format) < 0)
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR);
              goto cleanup;
            }

          /* if the sensor is not analog, this is most likely a bug in the
           * SDR, since we shouldn't be decoding a non-threshold sensor.
           */
          if (!IPMI_SDR_ANALOG_DATA_FORMAT_VALID (analog_data_format))
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_NON_ANALOG);
              rv = 0;
              goto cleanup;
            }

          /* if the sensor is non-linear, I just don't know what to do,
           * let the tool figure out what to output.
           */
          if (!IPMI_SDR_LINEARIZATION_IS_LINEAR (linearization))
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_NON_LINEAR);
              rv = 0;
              goto cleanup;
            }

          if (!(tmp_sensor_reading = (double *)malloc (sizeof (double))))
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_OUT_OF_MEMORY);
              goto cleanup;
            }

          if (ipmi_sensor_decode_value (r_exponent,
                                        b_exponent,
                                        m,
                                        b,
                                        linearization,
                                        analog_data_format,
                                        local_sensor_reading_raw,
                                        tmp_sensor_reading) < 0)
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR);
              goto cleanup;
            }

          *sensor_reading = tmp_sensor_reading;
        }
      rv = 1;
    }
  else if (event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_GENERIC_DISCRETE
           || event_reading_type_code_class ==  IPMI_EVENT_READING_TYPE_CODE_CLASS_SENSOR_SPECIFIC_DISCRETE)
    {
      /*
       * IPMI Workaround (achu)
       *
       * Discovered on HP Proliant DL380 G7
       * Discovered on HP ProLiant ML310 G5
       *
       * SDR records for some sensors give conflicting information.  A
       * threshold based sensor lists an event/reading type code for a
       * discrete sensor.  The analog data format indicates an
       * analog/threshold based sensor, however no threshold limits
       * for the sensor are listed in the SDR.
       *
       * To deal with this, if the analog data format and units
       * strongly suggest that a reading should occur with this
       * sensor, get the reading and return it.
       *
       * Note that this can only occur for full records, since
       * decoding data does not exist in compact records.
       */
      if (ctx->flags & IPMI_SENSOR_READ_FLAGS_DISCRETE_READING
          && record_type == IPMI_SDR_FORMAT_FULL_SENSOR_RECORD)
        {
          int8_t r_exponent, b_exponent;
          int16_t m, b;
          uint8_t linearization, analog_data_format;
          uint8_t sensor_units_percentage;
          uint8_t sensor_units_modifier;
          uint8_t sensor_units_rate;
          uint8_t sensor_base_unit_type;
          uint8_t sensor_modifier_unit_type;

          if (ipmi_sdr_parse_sensor_decoding_data (ctx->sdr_ctx,
                                                   sdr_record,
                                                   sdr_record_len,
                                                   &r_exponent,
                                                   &b_exponent,
                                                   &m,
                                                   &b,
                                                   &linearization,
                                                   &analog_data_format) < 0)
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR);
              goto cleanup;
            }

          if (ipmi_sdr_parse_sensor_units (ctx->sdr_ctx,
                                           sdr_record,
                                           sdr_record_len,
                                           &sensor_units_percentage,
                                           &sensor_units_modifier,
                                           &sensor_units_rate,
                                           &sensor_base_unit_type,
                                           &sensor_modifier_unit_type) < 0)
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR);
              goto cleanup;
            }

          /* if the sensor is not analog, this is normal expected
           * case, fallthrough to normal expectations
           */
          if (!IPMI_SDR_ANALOG_DATA_FORMAT_VALID (analog_data_format))
            {
              rv = 1;
              goto cleanup;
            }

          /* if the sensor units are not specified, this is the normal expected
           * case, fallthrough to normal expectations
           */
          if (sensor_units_percentage != IPMI_SDR_PERCENTAGE_YES
              && sensor_base_unit_type == IPMI_SENSOR_UNIT_UNSPECIFIED)
            {
              rv = 1;
              goto cleanup;
            }

          /* if the sensor is non-linear, I just don't know what to do,
           * let the tool figure out what to output.
           */
          if (!IPMI_SDR_LINEARIZATION_IS_LINEAR (linearization))
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_NON_LINEAR);
              rv = 0;
              goto cleanup;
            }

          if (!(tmp_sensor_reading = (double *)malloc (sizeof (double))))
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_OUT_OF_MEMORY);
              goto cleanup;
            }

          if (ipmi_sensor_decode_value (r_exponent,
                                        b_exponent,
                                        m,
                                        b,
                                        linearization,
                                        analog_data_format,
                                        local_sensor_reading_raw,
                                        tmp_sensor_reading) < 0)
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR);
              goto cleanup;
            }

          *sensor_reading = tmp_sensor_reading;
        }
      rv = 1;
    }
  else if (event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_OEM)
    /* nothing to do, sensor_event_bitmask already set */
    rv = 1;
  else
    rv = 0;

 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  if (rv <= 0)
    free (tmp_sensor_reading);
  return (rv);
}
static int
_simple_output_full_record (ipmi_sensors_state_data_t *state_data,
                            uint16_t record_id,
                            uint8_t sensor_number,
                            double *sensor_reading,
                            int event_message_output_type,
                            uint16_t sensor_event_bitmask,
                            char **event_message_list,
                            unsigned int event_message_list_len)
{
  char fmt[IPMI_SENSORS_FMT_BUFLEN + 1];
  uint8_t event_reading_type_code;
  double *lower_non_critical_threshold = NULL;
  double *upper_non_critical_threshold = NULL;
  double *lower_critical_threshold = NULL;
  double *upper_critical_threshold = NULL;
  double *lower_non_recoverable_threshold = NULL;
  double *upper_non_recoverable_threshold = NULL;
  int rv = -1;

  assert (state_data);
  assert (IPMI_SENSORS_EVENT_VALID (event_message_output_type));

  if (_simple_output_header (state_data,
                             record_id,
                             sensor_number,
                             event_message_output_type,
                             sensor_event_bitmask) < 0)
    goto cleanup;

  if (ipmi_sdr_parse_event_reading_type_code (state_data->sdr_ctx,
                                              NULL,
                                              0,
                                              &event_reading_type_code) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_event_reading_type_code: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }

  switch (ipmi_event_reading_type_code_class (event_reading_type_code))
    {
    case IPMI_EVENT_READING_TYPE_CODE_CLASS_THRESHOLD:
      if (!state_data->prog_data->args->quiet_readings)
        {
          char sensor_units_buf[IPMI_SENSORS_UNITS_BUFLEN+1];

          memset (sensor_units_buf, '\0', IPMI_SENSORS_UNITS_BUFLEN+1);
          if (get_sensor_units_output_string (state_data->pstate,
                                              state_data->sdr_ctx,
                                              sensor_units_buf,
                                              IPMI_SENSORS_UNITS_BUFLEN,
                                              state_data->prog_data->args->non_abbreviated_units) < 0)
            goto cleanup;

          memset (fmt, '\0', IPMI_SENSORS_FMT_BUFLEN + 1);

          if (sensor_reading)
            {
              if (state_data->prog_data->args->comma_separated_output)
                snprintf (fmt,
                          IPMI_SENSORS_FMT_BUFLEN,
                          ",%%.2f,%%s");
              else
                snprintf (fmt,
                          IPMI_SENSORS_FMT_BUFLEN,
                          " | %%-10.2f | %%-%ds",
                          state_data->column_width.sensor_units);
              
              pstdout_printf (state_data->pstate,
                              fmt,
                              _round_double2 (*sensor_reading),
                              sensor_units_buf);
            }
          else
            {
              if (state_data->prog_data->args->comma_separated_output)
                snprintf (fmt,
                          IPMI_SENSORS_FMT_BUFLEN,
                          ",%%s,%%s");
              else
                snprintf (fmt,
                          IPMI_SENSORS_FMT_BUFLEN,
                          " | %%-10s | %%-%ds",
                          state_data->column_width.sensor_units);
              
              pstdout_printf (state_data->pstate,
                              fmt,
                              IPMI_SENSORS_NA_STRING,
                              sensor_units_buf);
            }
        }

      if (state_data->prog_data->args->output_sensor_thresholds)
        {
          char thresholdfmt[IPMI_SENSORS_FMT_BUFLEN + 1];
          char nafmt[IPMI_SENSORS_FMT_BUFLEN + 1];

          if (ipmi_sensors_get_thresholds (state_data,
                                           &lower_non_critical_threshold,
                                           &lower_critical_threshold,
                                           &lower_non_recoverable_threshold,
                                           &upper_non_critical_threshold,
                                           &upper_critical_threshold,
                                           &upper_non_recoverable_threshold) < 0)
            goto cleanup;

          memset (fmt, '\0', IPMI_SENSORS_FMT_BUFLEN + 1);

          if (state_data->prog_data->args->comma_separated_output)
            {
              snprintf (thresholdfmt,
                        IPMI_SENSORS_FMT_BUFLEN,
                        ",%%.2f");

              snprintf (nafmt,
                        IPMI_SENSORS_FMT_BUFLEN,
                        ",%%s");
            }
          else
            {
              snprintf (thresholdfmt,
                        IPMI_SENSORS_FMT_BUFLEN,
                        " | %%-10.2f");

              snprintf (nafmt,
                        IPMI_SENSORS_FMT_BUFLEN,
                        " | %%-10s");
            }

          if (lower_non_recoverable_threshold)
            pstdout_printf (state_data->pstate,
                            thresholdfmt,
                            *lower_non_recoverable_threshold);
          else
            pstdout_printf (state_data->pstate,
                            nafmt,
                            IPMI_SENSORS_NA_STRING);

          if (lower_critical_threshold)
            pstdout_printf (state_data->pstate,
                            thresholdfmt,
                            *lower_critical_threshold);
          else
            pstdout_printf (state_data->pstate,
                            nafmt,
                            IPMI_SENSORS_NA_STRING);

          if (lower_non_critical_threshold)
            pstdout_printf (state_data->pstate,
                            thresholdfmt,
                            *lower_non_critical_threshold);
          else
            pstdout_printf (state_data->pstate,
                            nafmt,
                            IPMI_SENSORS_NA_STRING);
                          
          if (upper_non_critical_threshold)
            pstdout_printf (state_data->pstate,
                            thresholdfmt,
                            *upper_non_critical_threshold);
          else
            pstdout_printf (state_data->pstate,
                            nafmt,
                            IPMI_SENSORS_NA_STRING);

          if (upper_critical_threshold)
            pstdout_printf (state_data->pstate,
                            thresholdfmt,
                            *upper_critical_threshold);
          else
            pstdout_printf (state_data->pstate,
                            nafmt,
                            IPMI_SENSORS_NA_STRING);

          if (upper_non_recoverable_threshold)
            pstdout_printf (state_data->pstate,
                            thresholdfmt,
                            *upper_non_recoverable_threshold);
          else
            pstdout_printf (state_data->pstate,
                            nafmt,
                            IPMI_SENSORS_NA_STRING);
        }

      if (state_data->prog_data->args->comma_separated_output)
        pstdout_printf (state_data->pstate, ",");
      else
        pstdout_printf (state_data->pstate, " | ");

      if (ipmi_sensors_output_event_message_list (state_data,
                                                  event_message_output_type,
                                                  sensor_event_bitmask,
                                                  event_message_list,
                                                  event_message_list_len,
                                                  NULL,
                                                  0) < 0)
        goto cleanup;

      break;
    case IPMI_EVENT_READING_TYPE_CODE_CLASS_GENERIC_DISCRETE:
    case IPMI_EVENT_READING_TYPE_CODE_CLASS_SENSOR_SPECIFIC_DISCRETE:
    case IPMI_EVENT_READING_TYPE_CODE_CLASS_OEM:
    default:
      if (!state_data->prog_data->args->quiet_readings)
        {
          if (state_data->prog_data->args->common_args.section_specific_workaround_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_DISCRETE_READING
              && sensor_reading)
            {
              char sensor_units_buf[IPMI_SENSORS_UNITS_BUFLEN+1];

              memset (sensor_units_buf, '\0', IPMI_SENSORS_UNITS_BUFLEN+1);
              if (get_sensor_units_output_string (state_data->pstate,
                                                  state_data->sdr_ctx,
                                                  sensor_units_buf,
                                                  IPMI_SENSORS_UNITS_BUFLEN,
                                                  state_data->prog_data->args->non_abbreviated_units) < 0)
                goto cleanup;
              
              memset (fmt, '\0', IPMI_SENSORS_FMT_BUFLEN + 1);

              if (state_data->prog_data->args->comma_separated_output)
                snprintf (fmt,
                          IPMI_SENSORS_FMT_BUFLEN,
                          ",%%.2f,%%s");
              else
                snprintf (fmt,
                          IPMI_SENSORS_FMT_BUFLEN,
                          " | %%-10.2f | %%-%ds",
                          state_data->column_width.sensor_units);
                  
              pstdout_printf (state_data->pstate,
                              fmt,
                              _round_double2 (*sensor_reading),
                              sensor_units_buf);
            }
          else
            {
              memset (fmt, '\0', IPMI_SENSORS_FMT_BUFLEN + 1);

              if (state_data->prog_data->args->comma_separated_output)
                snprintf (fmt,
                          IPMI_SENSORS_FMT_BUFLEN,
                          ",%%s,%%s");
              else
                snprintf (fmt,
                          IPMI_SENSORS_FMT_BUFLEN,
                          " | %%-10s | %%-%ds",
                          state_data->column_width.sensor_units);
              
              pstdout_printf (state_data->pstate,
                              fmt,
                              IPMI_SENSORS_NA_STRING,
                              IPMI_SENSORS_NA_STRING);
            }
        }

      if (state_data->prog_data->args->output_sensor_thresholds)
        {
          if (state_data->prog_data->args->comma_separated_output)
            pstdout_printf (state_data->pstate,
                            ",%s,%s,%s,%s,%s,%s",
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING);
          else
            pstdout_printf (state_data->pstate,
                            " | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s",
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING,
                            IPMI_SENSORS_NA_STRING);
        }
 
      if (state_data->prog_data->args->comma_separated_output)
        pstdout_printf (state_data->pstate, ",");
      else
        pstdout_printf (state_data->pstate, " | ");
      
      if (ipmi_sensors_output_event_message_list (state_data,
                                                  event_message_output_type,
                                                  sensor_event_bitmask,
                                                  event_message_list,
                                                  event_message_list_len,
                                                  NULL,
                                                  0) < 0)
        goto cleanup;
      break;
    }

  rv = 0;
 cleanup:
  free (lower_non_critical_threshold);
  free (upper_non_critical_threshold);
  free (lower_critical_threshold);
  free (upper_critical_threshold);
  free (lower_non_recoverable_threshold);
  free (upper_non_recoverable_threshold);
  return (rv);
}
static int
_simple_output_header (ipmi_sensors_state_data_t *state_data,
                       uint16_t record_id,
                       uint8_t sensor_number,
                       int event_message_output_type,
                       uint16_t sensor_event_bitmask)
{
  char fmt[IPMI_SENSORS_FMT_BUFLEN + 1];
  char sensor_name[IPMI_SDR_MAX_SENSOR_NAME_LENGTH + 1];
  unsigned int sensor_name_flags = 0;
  const char *sensor_type_string;
  uint8_t event_reading_type_code;

  assert (state_data);
  assert (IPMI_SENSORS_EVENT_VALID (event_message_output_type));

  memset (sensor_name, '\0', IPMI_SDR_MAX_SENSOR_NAME_LENGTH + 1);
      
  if (!state_data->prog_data->args->shared_sensors)
    sensor_name_flags |= IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS;

  if (state_data->prog_data->args->entity_sensor_names)
    {
      if (ipmi_sdr_parse_entity_sensor_name (state_data->sdr_ctx,
                                             NULL,
                                             0,
                                             sensor_number,
                                             sensor_name_flags,
                                             sensor_name,
                                             IPMI_SDR_MAX_SENSOR_NAME_LENGTH) < 0)
        {
          pstdout_fprintf (state_data->pstate,
                           stderr,
                           "ipmi_sdr_parse_entity_sensor_name: %s\n",
                           ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
          return (-1);
        }
    }
  else
    {
      if (ipmi_sdr_parse_sensor_name (state_data->sdr_ctx,
                                      NULL,
                                      0,
                                      sensor_number,
                                      sensor_name_flags,
                                      sensor_name,
                                      IPMI_SDR_MAX_SENSOR_NAME_LENGTH) < 0)
        {
          pstdout_fprintf (state_data->pstate,
                           stderr,
                           "ipmi_sdr_parse_sensor_name: %s\n",
                           ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
          return (-1);
        }
    }
  
  memset (fmt, '\0', IPMI_SENSORS_FMT_BUFLEN + 1);
  if (state_data->prog_data->args->no_sensor_type_output)
    {
      if (state_data->prog_data->args->comma_separated_output)
        snprintf (fmt,
                  IPMI_SENSORS_FMT_BUFLEN,
                  "%%u,%%s");
      else
        snprintf (fmt,
                  IPMI_SENSORS_FMT_BUFLEN,
                  "%%-%du | %%-%ds",
                  state_data->column_width.record_id,
                  state_data->column_width.sensor_name);
      
      pstdout_printf (state_data->pstate,
                      fmt,
                      record_id,
                      sensor_name);
    }
  else
    {     
      uint8_t sensor_type;

      if (ipmi_sdr_parse_sensor_type (state_data->sdr_ctx,
                                      NULL,
                                      0,
                                      &sensor_type) < 0)
        {
          pstdout_fprintf (state_data->pstate,
                           stderr,
                           "ipmi_sdr_parse_sensor_type: %s\n",
                           ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
          return (-1);
        }
      
      if (state_data->prog_data->args->comma_separated_output)
        snprintf (fmt,
                  IPMI_SENSORS_FMT_BUFLEN,
                  "%%u,%%s,%%s");
      else
        snprintf (fmt,
                  IPMI_SENSORS_FMT_BUFLEN,
                  "%%-%du | %%-%ds | %%-%ds",
                  state_data->column_width.record_id,
                  state_data->column_width.sensor_name,
                  state_data->column_width.sensor_type);
      
      if ((state_data->prog_data->args->interpret_oem_data)
          && (ipmi_sdr_parse_event_reading_type_code (state_data->sdr_ctx,
                                                      NULL,
                                                      0,
                                                      &event_reading_type_code) >= 0))
        sensor_type_string = get_oem_sensor_type_output_string (sensor_type,
                                                                event_reading_type_code,
                                                                state_data->oem_data.manufacturer_id,
                                                                state_data->oem_data.product_id);
      else 
        sensor_type_string = get_sensor_type_output_string (sensor_type);
      
      pstdout_printf (state_data->pstate,
                      fmt,
                      record_id,
                      sensor_name,
                      sensor_type_string);
    }

  if (state_data->prog_data->args->output_sensor_state)
    {
      char *sensor_state_str = NULL;

      if (ipmi_sensors_get_sensor_state (state_data,
                                         event_message_output_type,
                                         sensor_event_bitmask,
                                         &sensor_state_str) < 0)
        return (-1);

      if (state_data->prog_data->args->comma_separated_output)
        snprintf (fmt,
                  IPMI_SENSORS_FMT_BUFLEN,
                  ",%%s");
      else
        snprintf (fmt,
                  IPMI_SENSORS_FMT_BUFLEN,
                  " | %%-8s");

      pstdout_printf (state_data->pstate,
                      fmt,
                      sensor_state_str);
    }
      
  return (0);
}
static int
_ipmimonitoring_legacy_simple_output_full_record (ipmi_sensors_state_data_t *state_data,
                                                  uint16_t record_id,
                                                  double *sensor_reading,
                                                  int event_message_output_type,
                                                  uint16_t sensor_event_bitmask,
                                                  char **event_message_list,
                                                  unsigned int event_message_list_len)
{
  int rv = -1;

  assert (state_data);
  assert (IPMI_SENSORS_EVENT_VALID (event_message_output_type));

  if (_ipmimonitoring_legacy_simple_output_header (state_data, record_id) < 0)
    goto cleanup;

  if (state_data->prog_data->args->output_sensor_state)
    {
      char *sensor_state_str = NULL;
      
      if (ipmi_sensors_get_sensor_state (state_data,
                                         event_message_output_type,
                                         sensor_event_bitmask,
                                         &sensor_state_str) < 0)
        goto cleanup;
      
      pstdout_printf (state_data->pstate,
                      " | %s",
                      sensor_state_str);
    }

  if (!state_data->prog_data->args->quiet_readings)
    {
      uint8_t event_reading_type_code;

      if (ipmi_sdr_parse_event_reading_type_code (state_data->sdr_ctx,
                                                  NULL,
                                                  0,
                                                  &event_reading_type_code) < 0)
        {
          pstdout_fprintf (state_data->pstate,
                           stderr,
                           "ipmi_sdr_parse_event_reading_type_code: %s\n",
                           ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
          goto cleanup;
        }
      
      switch (ipmi_event_reading_type_code_class (event_reading_type_code))
        {
        case IPMI_EVENT_READING_TYPE_CODE_CLASS_THRESHOLD:
          {
            char sensor_units_buf[IPMI_SENSORS_UNITS_BUFLEN+1];
            
            memset (sensor_units_buf, '\0', IPMI_SENSORS_UNITS_BUFLEN+1);
            if (get_sensor_units_output_string (state_data->pstate,
                                                state_data->sdr_ctx,
                                                sensor_units_buf,
                                                IPMI_SENSORS_UNITS_BUFLEN,
                                                0) < 0)
              goto cleanup;
            
            
            if (sensor_reading)
              pstdout_printf (state_data->pstate,
                              " | %s | %f\n",
                              sensor_units_buf,
                              *sensor_reading);
            else
              pstdout_printf (state_data->pstate,
                              " | %s | %s\n",
                              sensor_units_buf,
                              IPMIMONITORING_NA_STRING_LEGACY);
          }

          break;
          
        case IPMI_EVENT_READING_TYPE_CODE_CLASS_GENERIC_DISCRETE:
        case IPMI_EVENT_READING_TYPE_CODE_CLASS_SENSOR_SPECIFIC_DISCRETE:
        case IPMI_EVENT_READING_TYPE_CODE_CLASS_OEM:
        default:
          /* sensor units */
          pstdout_printf (state_data->pstate,
                          " | %s | ",
                          IPMIMONITORING_NA_STRING_LEGACY);
          
          if (ipmi_sensors_output_event_message_list (state_data,
                                                      event_message_output_type,
                                                      sensor_event_bitmask,
                                                      event_message_list,
                                                      event_message_list_len,
                                                      NULL,
                                                      0) < 0)
            goto cleanup;
          
          break;
        }
    }
  else
    pstdout_printf (state_data->pstate,
                    "\n");

  rv = 0;
 cleanup:
  return (rv);
}
static int
_legacy_simple_output_full_record (ipmi_sensors_state_data_t *state_data,
                                   uint16_t record_id,
                                   double *sensor_reading,
                                   int event_message_output_type,
                                   uint16_t sensor_event_bitmask,
                                   char **event_message_list,
                                   unsigned int event_message_list_len)
{
  uint8_t event_reading_type_code;
  double *lower_non_critical_threshold = NULL;
  double *upper_non_critical_threshold = NULL;
  double *lower_critical_threshold = NULL;
  double *upper_critical_threshold = NULL;
  double *lower_non_recoverable_threshold = NULL;
  double *upper_non_recoverable_threshold = NULL;
  int rv = -1;

  assert (state_data);
  assert (IPMI_SENSORS_EVENT_VALID (event_message_output_type));

  if (_legacy_simple_output_header (state_data, record_id) < 0)
    goto cleanup;

  if (ipmi_sdr_parse_event_reading_type_code (state_data->sdr_ctx,
                                              NULL,
                                              0,
                                              &event_reading_type_code) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_event_reading_type_code: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }

  switch (ipmi_event_reading_type_code_class (event_reading_type_code))
    {
    case IPMI_EVENT_READING_TYPE_CODE_CLASS_THRESHOLD:
      if (!state_data->prog_data->args->quiet_readings)
        {
          char sensor_units_buf[IPMI_SENSORS_UNITS_BUFLEN+1];
          double *lower_output_threshold = NULL;
          double *upper_output_threshold = NULL;

          memset (sensor_units_buf, '\0', IPMI_SENSORS_UNITS_BUFLEN+1);
          if (get_sensor_units_output_string (state_data->pstate,
                                              state_data->sdr_ctx,
                                              sensor_units_buf,
                                              IPMI_SENSORS_UNITS_BUFLEN,
                                              0) < 0)
            goto cleanup;

          if (ipmi_sensors_get_thresholds (state_data,
                                           &lower_non_critical_threshold,
                                           &lower_critical_threshold,
                                           &lower_non_recoverable_threshold,
                                           &upper_non_critical_threshold,
                                           &upper_critical_threshold,
                                           &upper_non_recoverable_threshold) < 0)
            goto cleanup;

          if (sensor_reading)
            pstdout_printf (state_data->pstate,
                            "%.2f %s ",
                            _round_double2 (*sensor_reading),
                            sensor_units_buf);
          else
            pstdout_printf (state_data->pstate,
                            "%s ",
                            IPMI_SENSORS_NA_STRING_LEGACY);
          
          /* default output is critical thresholds, if those aren't
           * available, move to non-recoverable, and if those aren't
           * available, move on to non-critical.
           */
          
          if (lower_critical_threshold || upper_critical_threshold)
            {
              lower_output_threshold = lower_critical_threshold;
              upper_output_threshold = upper_critical_threshold;
            }
          else if (lower_non_recoverable_threshold || upper_non_recoverable_threshold)
            {
              lower_output_threshold = lower_non_recoverable_threshold;
              upper_output_threshold = upper_non_recoverable_threshold;
            }
          else if (lower_non_critical_threshold || upper_non_critical_threshold)
            {
              lower_output_threshold = lower_non_critical_threshold;
              upper_output_threshold = upper_non_critical_threshold;
            }
          
          if (lower_output_threshold)
            pstdout_printf (state_data->pstate,
                            "(%.2f/",
                            _round_double2 (*lower_output_threshold));
          else
            pstdout_printf (state_data->pstate, "(%s/", IPMI_SENSORS_NA_STRING_LEGACY);
          
          if (upper_output_threshold)
            pstdout_printf (state_data->pstate,
                            "%.2f): ",
                            _round_double2 (*upper_output_threshold));
          else
            pstdout_printf (state_data->pstate, "%s): ", IPMI_SENSORS_NA_STRING_LEGACY);
        }
      /* fall through and also output event messages */
    case IPMI_EVENT_READING_TYPE_CODE_CLASS_GENERIC_DISCRETE:
    case IPMI_EVENT_READING_TYPE_CODE_CLASS_SENSOR_SPECIFIC_DISCRETE:
    case IPMI_EVENT_READING_TYPE_CODE_CLASS_OEM:
    default:
      if (ipmi_sensors_output_event_message_list (state_data,
                                                  event_message_output_type,
                                                  sensor_event_bitmask,
                                                  event_message_list,
                                                  event_message_list_len,
                                                  NULL,
                                                  0) < 0)
        goto cleanup;
      break;
    }

  rv = 0;
 cleanup:
  free (lower_non_critical_threshold);
  free (upper_non_critical_threshold);
  free (lower_critical_threshold);
  free (upper_critical_threshold);
  free (lower_non_recoverable_threshold);
  free (upper_non_recoverable_threshold);
  return (rv);
}