static int
_ipmi_monitoring_sdr_cache_retrieve (ipmi_monitoring_ctx_t c,
                                     const char *hostname,
                                     char *filename,
				     unsigned int sdr_create_flags)
{
  assert (c);
  assert (c->magic == IPMI_MONITORING_MAGIC);
  assert (c->sdr_ctx);
  assert (c->ipmi_ctx);
  assert (filename && strlen (filename));

  if (ipmi_sdr_cache_create (c->sdr_ctx,
                             c->ipmi_ctx,
                             filename,
			     sdr_create_flags,
                             NULL,
                             NULL) < 0)
    {
      IPMI_MONITORING_DEBUG (("ipmi_sdr_cache_create: %s", ipmi_sdr_ctx_errormsg (c->sdr_ctx)));
      if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_FILESYSTEM)
        c->errnum = IPMI_MONITORING_ERR_SDR_CACHE_FILESYSTEM;
      else if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_PERMISSION)
        c->errnum = IPMI_MONITORING_ERR_SDR_CACHE_PERMISSION;
      else if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_IPMI_ERROR)
        ipmi_monitoring_ipmi_ctx_error_convert (c);
      else if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_SYSTEM_ERROR)
        c->errnum = IPMI_MONITORING_ERR_SYSTEM_ERROR;
      else
        c->errnum = IPMI_MONITORING_ERR_INTERNAL_ERROR;
      return (-1);
    }

  return (0);
}
int
ipmi_sdr_cache_sdr_version (ipmi_sdr_ctx_t ctx, uint8_t *sdr_version)
{
  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (!sdr_version)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  *sdr_version = ctx->sdr_version;
  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (0);
}
int
ipmi_sdr_cache_record_count (ipmi_sdr_ctx_t ctx, uint16_t *record_count)
{
  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (!record_count)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  *record_count = ctx->record_count;
  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (0);
}
int
ipmi_sdr_cache_most_recent_erase_timestamp (ipmi_sdr_ctx_t ctx, uint32_t *most_recent_erase_timestamp)
{
  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (!most_recent_erase_timestamp)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  *most_recent_erase_timestamp = ctx->most_recent_erase_timestamp;
  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (0);
}
int
ipmi_sdr_cache_next (ipmi_sdr_ctx_t ctx)
{
  unsigned int record_length;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  record_length = (uint8_t)((ctx->sdr_cache + ctx->current_offset.offset)[IPMI_SDR_RECORD_LENGTH_INDEX]);

  if ((ctx->current_offset.offset + record_length + IPMI_SDR_RECORD_HEADER_LENGTH) >= ctx->records_end_offset)
    return (0);

  _sdr_set_current_offset (ctx, ctx->current_offset.offset + IPMI_SDR_RECORD_HEADER_LENGTH + record_length);

  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (1);
}
Beispiel #6
0
int
ipmi_sdr_stats_entity_instance_unique (ipmi_sdr_ctx_t ctx, uint8_t entity_id)
{
  int rv = -1;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  if (!ctx->stats_compiled)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_STATS_NOT_COMPILED);
      return (-1);
    }

  rv = ctx->entity_counts[entity_id].entity_instances_count;
  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (rv);
}
Beispiel #7
0
int
ipmi_sdr_stats_compile (ipmi_sdr_ctx_t ctx)
{
  int rv = -1;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  if (ctx->stats_compiled)
    goto out;

  if (ipmi_sdr_cache_iterate (ctx,
			      _sdr_stat_callback,
			      NULL) < 0)
    goto cleanup;

  ctx->stats_compiled = 1;

 out:
  rv = 0;
  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
 cleanup:
  return (rv);
}
int
ipmi_sdr_cache_search_record_id (ipmi_sdr_ctx_t ctx, uint16_t record_id)
{
  off_t offset;
  int found = 0;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  offset = ctx->records_start_offset;
  while (offset < ctx->records_end_offset)
    {
      uint8_t *ptr = ctx->sdr_cache + offset;
      uint16_t record_id_current;
      unsigned int record_length;

      /* Record ID stored little-endian */
      record_id_current = (uint16_t)ptr[IPMI_SDR_RECORD_ID_INDEX_LS] & 0xFF;
      record_id_current |= ((uint16_t)ptr[IPMI_SDR_RECORD_ID_INDEX_MS] & 0xFF) << 8;

      if (record_id == record_id_current)
        {
          found++;
	  _sdr_set_current_offset (ctx, offset);
          break;
        }

      record_length = (uint8_t)((ctx->sdr_cache + offset)[IPMI_SDR_RECORD_LENGTH_INDEX]);

      if ((offset + record_length + IPMI_SDR_RECORD_HEADER_LENGTH) >= ctx->records_end_offset)
	break;

      offset += IPMI_SDR_RECORD_HEADER_LENGTH;
      offset += record_length;
    }

  if (!found)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_NOT_FOUND);
      return (-1);
    }

  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (0);
}
static int
_ipmi_monitoring_sdr_cache_delete (ipmi_monitoring_ctx_t c,
                                   const char *hostname,
                                   char *filename)
{
  assert (c);
  assert (c->magic == IPMI_MONITORING_MAGIC);
  assert (c->sdr_ctx);

  if (ipmi_sdr_cache_delete (c->sdr_ctx, filename) < 0)
    {
      if (ipmi_sdr_ctx_errnum (c->sdr_ctx) !=  IPMI_SDR_ERR_FILENAME_INVALID)
        {
          IPMI_MONITORING_DEBUG (("ipmi_sdr_cache_delete: %s", ipmi_sdr_ctx_errormsg (c->sdr_ctx)));
          if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_PERMISSION)
            c->errnum = IPMI_MONITORING_ERR_SDR_CACHE_PERMISSION;
          else
            c->errnum = IPMI_MONITORING_ERR_INTERNAL_ERROR;
          return (-1);
        }
    }

  return (0);
}
int
ipmi_sdr_cache_delete (ipmi_sdr_ctx_t ctx, const char *filename)
{
  int rv = -1;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (!filename)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_UNINITIALIZED)
    {
      if (ctx->operation == IPMI_SDR_OPERATION_READ_CACHE)
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CONTEXT_PERFORMING_OTHER_OPERATION);
      else
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
      return (-1);
    }

  ctx->operation = IPMI_SDR_OPERATION_DELETE_CACHE;

  if (unlink (filename) < 0)
    {
      /* If there is no file (ENOENT), its ok */
      if (errno != ENOENT)
        {
          SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
	  goto cleanup;
        }
    }

  rv = 0;
  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
 cleanup:
  ctx->operation = IPMI_SDR_OPERATION_UNINITIALIZED;
  return (rv);
}
int
ipmi_sdr_cache_seek (ipmi_sdr_ctx_t ctx, unsigned int index)
{
  off_t offset;
  unsigned int i;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  if (index >= ctx->record_count)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  offset = ctx->records_start_offset;
  for (i = 0; i < index; i++)
    {
      unsigned int record_length;

      record_length = (uint8_t)((ctx->sdr_cache + offset)[IPMI_SDR_RECORD_LENGTH_INDEX]);

      if ((offset + record_length + IPMI_SDR_RECORD_HEADER_LENGTH) >= ctx->records_end_offset)
	break;

      offset += IPMI_SDR_RECORD_HEADER_LENGTH;
      offset += record_length;
    }

  _sdr_set_current_offset (ctx, offset);

  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (0);
}
int
ipmi_sdr_cache_first (ipmi_sdr_ctx_t ctx)
{
  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  _sdr_set_current_offset (ctx, ctx->records_start_offset);

  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (0);
}
int
ipmi_sdr_cache_create (ipmi_sdr_ctx_t ctx,
                       ipmi_ctx_t ipmi_ctx,
                       const char *filename,
                       int cache_create_flags,
                       Ipmi_Sdr_Cache_Create_Callback create_callback,
                       void *create_callback_data)
{
    int open_flags;
    uint8_t sdr_version;
    uint16_t record_count, reservation_id, record_id, next_record_id;
    uint32_t most_recent_addition_timestamp, most_recent_erase_timestamp;
    unsigned int record_count_written = 0;
    unsigned int total_bytes_written = 0;
    uint16_t *record_ids = NULL;
    unsigned int record_ids_count = 0;
    unsigned int cache_create_flags_mask = (IPMI_SDR_CACHE_CREATE_FLAGS_OVERWRITE
                                            | IPMI_SDR_CACHE_CREATE_FLAGS_DUPLICATE_RECORD_ID
                                            | IPMI_SDR_CACHE_CREATE_FLAGS_ASSUME_MAX_SDR_RECORD_COUNT);
    uint8_t trailer_checksum = 0;
    int fd = -1;
    int rv = -1;

    if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
        ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
        return (-1);
    }

    /* Version cannot be 0h according to the IPMI spec */
    if (!ipmi_ctx
            || !filename
            || (strlen (filename) > MAXPATHLEN)
            || (cache_create_flags & ~cache_create_flags_mask))
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
        return (-1);
    }

    if (ctx->operation != IPMI_SDR_OPERATION_UNINITIALIZED)
    {
        if (ctx->operation == IPMI_SDR_OPERATION_READ_CACHE)
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CONTEXT_PERFORMING_OTHER_OPERATION);
        else
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
        return (-1);
    }

    ctx->operation = IPMI_SDR_OPERATION_CREATE_CACHE;

    if (cache_create_flags & IPMI_SDR_CACHE_CREATE_FLAGS_OVERWRITE)
        open_flags = O_CREAT | O_TRUNC | O_WRONLY;
    else
        open_flags = O_CREAT | O_EXCL | O_WRONLY;

    if ((fd = open (filename, open_flags, 0644)) < 0)
    {
        if (!(cache_create_flags & IPMI_SDR_CACHE_CREATE_FLAGS_OVERWRITE)
                && errno == EEXIST)
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_CACHE_EXISTS);
        else if (errno == EPERM
                 || errno == EACCES
                 || errno == EISDIR
                 || errno == EROFS)
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PERMISSION);
        else if (errno == ENAMETOOLONG
                 || errno == ENOENT
                 || errno == ELOOP)
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_FILENAME_INVALID);
        else if (errno == ENOSPC
                 || errno == EMFILE
                 || errno == ENFILE)
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_FILESYSTEM);
        else
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
        goto cleanup;
    }

    if (sdr_info (ctx,
                  ipmi_ctx,
                  &sdr_version,
                  &record_count,
                  &most_recent_addition_timestamp,
                  &most_recent_erase_timestamp) < 0)
        goto cleanup;

    if (!record_count)
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_INVALID_RECORD_COUNT);
        goto cleanup;
    }

    if (_sdr_cache_header_write (ctx,
                                 ipmi_ctx,
                                 fd,
                                 &total_bytes_written,
                                 sdr_version,
                                 record_count,
                                 most_recent_addition_timestamp,
                                 most_recent_erase_timestamp) < 0)
        goto cleanup;

    /* Version cannot be 0h according to the IPMI spec, but we accept it regardless */
    ctx->sdr_version = sdr_version;
    ctx->record_count = record_count;
    ctx->most_recent_addition_timestamp = most_recent_addition_timestamp;
    ctx->most_recent_erase_timestamp = most_recent_erase_timestamp;

    if (cache_create_flags & IPMI_SDR_CACHE_CREATE_FLAGS_DUPLICATE_RECORD_ID)
    {
        if (!(record_ids = (uint16_t *)malloc (ctx->record_count * sizeof (uint16_t))))
        {
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_OUT_OF_MEMORY);
            goto cleanup;
        }
        record_ids_count = 0;
    }

    if (_sdr_cache_reservation_id (ctx,
                                   ipmi_ctx,
                                   &reservation_id) < 0)
        goto cleanup;

    next_record_id = IPMI_SDR_RECORD_ID_FIRST;
    while (next_record_id != IPMI_SDR_RECORD_ID_LAST)
    {
        uint8_t record_buf[IPMI_SDR_MAX_RECORD_LENGTH];
        int record_len;

        if (record_count_written >= ctx->record_count)
        {
            /* IPMI Workaround
             *
             * Discovered on unspecified Inspur motherboard
             *
             * SDR record reading is broken, the IPMI_SDR_RECORD_ID_LAST
             * record id never occurs.  So this workaround allows the
             * user to not error out and avoids this loop from looping
             * infinitely.
             *
             */

            if (cache_create_flags & IPMI_SDR_CACHE_CREATE_FLAGS_ASSUME_MAX_SDR_RECORD_COUNT)
                break;

            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_INVALID_RECORD_COUNT);
            goto cleanup;
        }

        record_id = next_record_id;
        if ((record_len = _sdr_cache_get_record (ctx,
                          ipmi_ctx,
                          record_id,
                          record_buf,
                          IPMI_SDR_MAX_RECORD_LENGTH,
                          &reservation_id,
                          &next_record_id)) < 0)
            goto cleanup;

        if (record_len)
        {
            if (ctx->flags & IPMI_SDR_FLAGS_DEBUG_DUMP)
            {
                const char *record_str;

                if ((record_str = sdr_record_type_str (ctx,
                                                       record_buf,
                                                       record_len)))
                {
                    char hdrbuf[IPMI_SDR_CACHE_DEBUG_BUFLEN];

                    debug_hdr_str (DEBUG_UTIL_TYPE_NONE,
                                   DEBUG_UTIL_DIRECTION_NONE,
                                   DEBUG_UTIL_FLAGS_DEFAULT,
                                   record_str,
                                   hdrbuf,
                                   IPMI_SDR_CACHE_DEBUG_BUFLEN);

                    ipmi_dump_sdr_record (STDERR_FILENO,
                                          ctx->debug_prefix,
                                          hdrbuf,
                                          NULL,
                                          record_buf,
                                          record_len);
                }
            }

            if (_sdr_cache_record_write (ctx,
                                         fd,
                                         &total_bytes_written,
                                         record_ids,
                                         &record_ids_count,
                                         record_buf,
                                         record_len,
                                         &trailer_checksum) < 0)
                goto cleanup;

            record_count_written++;

            if (create_callback)
                (*create_callback)(ctx->sdr_version,
                                   ctx->record_count,
                                   ctx->most_recent_addition_timestamp,
                                   ctx->most_recent_erase_timestamp,
                                   record_id,
                                   create_callback_data);
        }
    }

    if (record_count_written != ctx->record_count)
    {
        /*
         * IPMI Workaround (achu)
         *
         * Discovered on Fujitsu RX 100
         * Discovered on Fujitsu RX300/200-S8
         *
         * The record_count listed from the Get SDR Repository Info command
         * is not consistent with the length of SDR records stored.
         *
         * We will assume that if we reached the end of the SDR record
         * list (i.e. next_record_id == 0xFFFF), a non-zero number of
         * records were written, it's ok and we can continue on.
         */
        if (next_record_id == IPMI_SDR_RECORD_ID_LAST
                && record_count_written)
        {
            unsigned int total_bytes_written_temp = 0;

            ctx->record_count = record_count_written;

            /* need to seek back to the beginning of the file and
             * re-write the header info with the correct number of
             * records
             */

            if (lseek (fd, 0, SEEK_SET) < 0)
            {
                SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
                goto cleanup;
            }

            if (_sdr_cache_header_write (ctx,
                                         ipmi_ctx,
                                         fd,
                                         &total_bytes_written_temp,
                                         ctx->sdr_version,
                                         ctx->record_count,
                                         ctx->most_recent_addition_timestamp,
                                         ctx->most_recent_erase_timestamp) < 0)
                goto cleanup;

            /* need to seek back to the end of the file to write the
             * trailer below
             */
            if (lseek (fd, 0, SEEK_END) < 0)
            {
                SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
                goto cleanup;
            }
        }
        else
        {
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_INVALID_RECORD_COUNT);
            goto cleanup;
        }
    }

    if (_sdr_cache_trailer_write (ctx,
                                  ipmi_ctx,
                                  fd,
                                  total_bytes_written,
                                  trailer_checksum) < 0)
        goto cleanup;

    if (fsync (fd) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        goto cleanup;
    }

    if (close (fd) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        goto cleanup;
    }
    fd = -1;

    rv = 0;
    ctx->errnum = IPMI_SDR_ERR_SUCCESS;
cleanup:
    ctx->operation = IPMI_SDR_OPERATION_UNINITIALIZED;
    if (fd >= 0)
    {
        /* If the cache create never completed, try to remove the file */
        /* ignore potential error, cleanup path */
        unlink (filename);
        /* ignore potential error, cleanup path */
        close (fd);
    }
    free (record_ids);
    sdr_init_ctx (ctx);
    return (rv);
}
int
ipmi_monitoring_sdr_cache_load (ipmi_monitoring_ctx_t c,
                                const char *hostname,
				unsigned int sdr_create_flags)
{
  char filename[MAXPATHLEN+1];

  assert (c);
  assert (c->magic == IPMI_MONITORING_MAGIC);
  assert (c->ipmi_ctx);

  memset (filename, '\0', MAXPATHLEN + 1);

  if (_ipmi_monitoring_sdr_cache_filename (c, hostname, filename, MAXPATHLEN + 1) < 0)
    goto cleanup;

  if (_ipmi_monitoring_sdr_ctx_init (c, hostname) < 0)
    goto cleanup;

  if (ipmi_sdr_cache_open (c->sdr_ctx,
                           c->ipmi_ctx,
                           filename) < 0)
    {
      if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST)
        {
          if (_ipmi_monitoring_sdr_cache_retrieve (c, hostname, filename, sdr_create_flags) < 0)
            goto cleanup;
        }
      else if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_CACHE_INVALID
               || ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_CACHE_OUT_OF_DATE)
        {
          if (_ipmi_monitoring_sdr_cache_delete (c, hostname, filename) < 0)
            goto cleanup;

          if (_ipmi_monitoring_sdr_cache_retrieve (c, hostname, filename, sdr_create_flags) < 0)
            goto cleanup;
        }
      else if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_FILESYSTEM)
        {
          c->errnum = IPMI_MONITORING_ERR_SDR_CACHE_FILESYSTEM;
          goto cleanup;
        }
      else if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_PERMISSION)
        {
          c->errnum = IPMI_MONITORING_ERR_SDR_CACHE_PERMISSION;
          goto cleanup;
        }
      else
        {
          IPMI_MONITORING_DEBUG (("ipmi_sdr_cache_open: %s", ipmi_sdr_ctx_errormsg (c->sdr_ctx)));
          c->errnum = IPMI_MONITORING_ERR_INTERNAL_ERROR;
          goto cleanup;
        }

      /* 2nd try after the sdr was retrieved*/
      if (ipmi_sdr_cache_open (c->sdr_ctx,
                               c->ipmi_ctx,
                               filename) < 0)
        {
          if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_FILESYSTEM)
            {
              c->errnum = IPMI_MONITORING_ERR_SDR_CACHE_FILESYSTEM;
              goto cleanup;
            }
          else if (ipmi_sdr_ctx_errnum (c->sdr_ctx) == IPMI_SDR_ERR_PERMISSION)
            {
              c->errnum = IPMI_MONITORING_ERR_SDR_CACHE_PERMISSION;
              goto cleanup;
            }
          else
            {
              IPMI_MONITORING_DEBUG (("ipmi_sdr_cache_open: %s", ipmi_sdr_ctx_errormsg (c->sdr_ctx)));
              c->errnum = IPMI_MONITORING_ERR_INTERNAL_ERROR;
              goto cleanup;
            }
        }
    }

  return (0);

 cleanup:
  if (strlen (filename))
    ipmi_sdr_cache_delete (c->sdr_ctx, filename);
  ipmi_sdr_ctx_destroy (c->sdr_ctx);
  c->sdr_ctx = NULL;
  return (-1);
}
Beispiel #15
0
int
ipmi_sdr_parse_sensor_name (ipmi_sdr_ctx_t ctx,
			    const void *sdr_record,
			    unsigned int sdr_record_len,
			    uint8_t sensor_number,
			    unsigned int flags,
			    char *buf,
			    unsigned int buflen)
{
  char id_string[IPMI_SDR_MAX_ID_STRING_LENGTH + 1];
  char device_id_string[IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1];
  char *id_string_ptr = NULL;
  uint8_t record_type;
  unsigned int flags_mask = (IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS);

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  if (((sdr_record_len && !sdr_record_len)
       || (!sdr_record && sdr_record_len))
      || (flags & ~flags_mask)
      || !buf
      || !buflen)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  memset (buf, '\0', buflen);

  if (ipmi_sdr_parse_record_id_and_type (ctx,
					 sdr_record,
					 sdr_record_len,
                                         NULL,
                                         &record_type) < 0)
    return (-1);

  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)
    {
      memset (id_string, '\0', IPMI_SDR_MAX_ID_STRING_LENGTH + 1);

      if (ipmi_sdr_parse_id_string (ctx,
				    sdr_record,
				    sdr_record_len,
				    id_string,
                                    IPMI_SDR_MAX_ID_STRING_LENGTH) < 0)
	return (-1);

      id_string_ptr = id_string;
    }
  else if (record_type == IPMI_SDR_FORMAT_GENERIC_DEVICE_LOCATOR_RECORD
	   || record_type == IPMI_SDR_FORMAT_FRU_DEVICE_LOCATOR_RECORD
           || record_type == IPMI_SDR_FORMAT_MANAGEMENT_CONTROLLER_DEVICE_LOCATOR_RECORD)
    {
      memset (device_id_string, '\0', IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1);

      if (ipmi_sdr_parse_device_id_string (ctx,
					   sdr_record,
					   sdr_record_len,
                                           device_id_string,
                                           IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH) < 0)
	return (-1);
      
      id_string_ptr = device_id_string;
    }
  else
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARSE_INVALID_SDR_RECORD);
      return (-1);
    }

  /* special case if sensor sharing is involved */
  if ((record_type == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
       || record_type == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD)
      && !(flags & IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS))
    {
      if (_get_shared_sensor_name (ctx,
				   sdr_record,
				   sdr_record_len,
				   sensor_number,
				   id_string_ptr,
				   buf,
				   buflen) < 0)
	return (-1);
    }
  else
    snprintf (buf,
	      buflen,
	      "%s",
	      id_string_ptr);

  return (0);
}
Beispiel #16
0
int
ipmi_sdr_parse_entity_sensor_name (ipmi_sdr_ctx_t ctx,
				   const void *sdr_record,
				   unsigned int sdr_record_len,
				   uint8_t sensor_number,
				   unsigned int flags,
				   char *buf,
				   unsigned int buflen)
{
  char id_string[IPMI_SDR_MAX_ID_STRING_LENGTH + 1];
  char device_id_string[IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1];
  char entity_name_buf[IPMI_SDR_ENTITY_NAME_BUFLEN + 1];
  char *id_string_ptr = NULL;
  uint8_t entity_id, entity_instance, entity_instance_type;
  const char *entity_id_str;
  uint8_t record_type;
  unsigned int flags_mask = (IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS
			     | IPMI_SDR_SENSOR_NAME_FLAGS_ALWAYS_OUTPUT_INSTANCE_NUMBER);

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  if (((sdr_record_len && !sdr_record_len)
       || (!sdr_record && sdr_record_len))
      || (flags & ~flags_mask)
      || !buf
      || !buflen)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  memset (buf, '\0', buflen);
  memset (entity_name_buf, '\0', IPMI_SDR_ENTITY_NAME_BUFLEN + 1);

  if (ipmi_sdr_parse_record_id_and_type (ctx,
					 sdr_record,
					 sdr_record_len,
                                         NULL,
                                         &record_type) < 0)
    return (-1);

  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)
    {
      memset (id_string, '\0', IPMI_SDR_MAX_ID_STRING_LENGTH + 1);

      if (ipmi_sdr_parse_id_string (ctx,
				    sdr_record,
				    sdr_record_len,
				    id_string,
                                    IPMI_SDR_MAX_ID_STRING_LENGTH) < 0)
	return (-1);

      id_string_ptr = id_string;
    }
  else if (record_type == IPMI_SDR_FORMAT_GENERIC_DEVICE_LOCATOR_RECORD
           || record_type == IPMI_SDR_FORMAT_MANAGEMENT_CONTROLLER_DEVICE_LOCATOR_RECORD)
    {
      memset (device_id_string, '\0', IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1);

      if (ipmi_sdr_parse_device_id_string (ctx,
					   sdr_record,
					   sdr_record_len,
                                           device_id_string,
                                           IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH) < 0)
	return (-1);
      
      id_string_ptr = device_id_string;
    }
  else
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARSE_INVALID_SDR_RECORD);
      return (-1);
    }

  if (ipmi_sdr_parse_entity_id_instance_type (ctx,
					      sdr_record,
					      sdr_record_len,
                                              &entity_id,
                                              &entity_instance,
                                              &entity_instance_type) < 0)
    return (-1);

  /* Table 39-1
   *
   * "It is recommended that console software subtract 60h when
   * presenting device-relative Entity Instance values, and present
   * the Entity Instance number along with an ID for the device
   * providing the interface to the entity."
   *
   * achu: For the time being we do not output the device providing
   * the interface, only the right instance number.  Adjust later if
   * necessary.
   */

  if (IPMI_ENTITY_INSTANCE_DEVICE_RELATIVE (entity_instance))
    entity_instance -= IPMI_ENTITY_INSTANCE_DEVICE_RELATIVE_MIN;

  entity_id_str = ipmi_get_entity_id_string (entity_id);

  /* a few special cases, for entity_ids are special, the vendor has
   * specifically stated there is no "entity" associated with this sdr
   * record
   */
  if (entity_id == IPMI_ENTITY_ID_UNSPECIFIED
      || entity_id == IPMI_ENTITY_ID_OTHER
      || entity_id == IPMI_ENTITY_ID_UNKNOWN)
    snprintf (buf,
	      buflen,
	      "%s",
	      id_string_ptr);
  else
    {
      if (ipmi_sdr_stats_compile (ctx) < 0)
	return (-1);

      if (ipmi_sdr_stats_entity_instance_unique (ctx, entity_id) > 1)
        {
          /* special case if sensor sharing is involved */
          if ((record_type == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
               || record_type == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD)
              && !(flags & IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS))
            {
	      uint8_t share_count;
	      uint8_t entity_instance_sharing;
	      char sensor_name_buf[IPMI_SDR_MAX_SENSOR_NAME_LENGTH + 1];

	      if (ipmi_sdr_parse_sensor_record_sharing (ctx,
							sdr_record,
							sdr_record_len,
							&share_count,
							NULL,
							NULL,
							&entity_instance_sharing) < 0)
		return (-1);
      
	      if (share_count > 1
		  && entity_instance_sharing == IPMI_SDR_ENTITY_INSTANCE_INCREMENTS_FOR_EACH_SHARED_RECORD)
		{
		  uint8_t sensor_number_base;
      
		  if (ipmi_sdr_parse_sensor_number (ctx,
						    sdr_record,
						    sdr_record_len,
						    &sensor_number_base) < 0)
		    return (-1);
      
		  /* I guess it's a bug if the sensor number passed in is bad */
		  if (sensor_number >= sensor_number_base)
		    entity_instance += (sensor_number - sensor_number_base);
		  else
		    goto fallthrough;
		}

	      memset (sensor_name_buf, '\0', IPMI_SDR_MAX_SENSOR_NAME_LENGTH + 1);
	      
	      if (_get_shared_sensor_name (ctx,
					   sdr_record,
					   sdr_record_len,
					   sensor_number,
					   id_string_ptr,
					   sensor_name_buf,
					   IPMI_SDR_MAX_SENSOR_NAME_LENGTH) < 0)
		return (-1);

	      snprintf (entity_name_buf,
			IPMI_SDR_ENTITY_NAME_BUFLEN,
			"%s %u",
			entity_id_str,
			entity_instance);

	      /* In odd chance the strings end up identical */
	      if (!strcasecmp (entity_name_buf, sensor_name_buf))
		snprintf (buf,
			  buflen,
			  "%s",
			  sensor_name_buf);
	      else
		snprintf (buf,
			  buflen,
			  "%s %s",
			  entity_name_buf,
			  sensor_name_buf);
	    }
	  else
	    {
	    fallthrough:
	      snprintf (entity_name_buf,
			IPMI_SDR_ENTITY_NAME_BUFLEN,
			"%s %u",
			entity_id_str,
			entity_instance);
	      
	      /* In odd chance the strings end up identical */
	      if (!strcasecmp (entity_name_buf, id_string_ptr))
		snprintf (buf,
			  buflen,
			  "%s",
			  id_string_ptr);
	      else
		snprintf (buf,
			  buflen,
			  "%s %s",
			  entity_name_buf,
			  id_string_ptr);
	    }
	}
      else
	{
	  if (flags & IPMI_SDR_SENSOR_NAME_FLAGS_ALWAYS_OUTPUT_INSTANCE_NUMBER)
	    {
	      snprintf (entity_name_buf,
			IPMI_SDR_ENTITY_NAME_BUFLEN,
			"%s %u",
			entity_id_str,
			entity_instance);
	      
	      /* In odd chance the strings end up identical */
	      if (!strcasecmp (entity_name_buf, id_string_ptr))
		snprintf (buf,
			  buflen,
			  "%s",
			  id_string_ptr);
	      else
		snprintf (buf,
			  buflen,
			  "%s %s",
			  entity_name_buf,
			  id_string_ptr);
	    }
	  else
	    {
	      /* In odd chance the strings end up identical */
	      if (!strcasecmp (entity_id_str, id_string_ptr))
		snprintf (buf,
			  buflen,
			  "%s",
			  id_string_ptr);
	      else
		snprintf (buf,
			  buflen,
			  "%s %s",
			  entity_id_str,
			  id_string_ptr);
	    }
	}
    }

  return (0);
}
int
ipmi_sdr_cache_search_sensor (ipmi_sdr_ctx_t ctx, uint8_t sensor_number, uint8_t sensor_owner_id)
{
  off_t offset;
  int found = 0;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  offset = ctx->records_start_offset;
  while (offset < ctx->records_end_offset)
    {
      uint8_t *ptr = ctx->sdr_cache + offset;
      uint8_t record_type_current;
      unsigned int record_length;

      record_type_current = ptr[IPMI_SDR_RECORD_TYPE_INDEX];

      if (record_type_current == IPMI_SDR_FORMAT_FULL_SENSOR_RECORD
          || record_type_current == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
          || record_type_current == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD)
        {
          uint8_t sensor_number_current;
          uint8_t sensor_owner_id_current;

          sensor_owner_id_current = ptr[IPMI_SDR_RECORD_SENSOR_OWNER_ID_INDEX];
          sensor_number_current = ptr[IPMI_SDR_RECORD_SENSOR_NUMBER_INDEX];

          if (sensor_owner_id_current == sensor_owner_id
              && sensor_number_current == sensor_number)
            {
              found++;
	      _sdr_set_current_offset (ctx, offset);
              break;
            }

          /* Compact sensor records can do record sharing, so check
           * for this case if the sensor_owner_id matches up.
           */
          if (sensor_owner_id_current == sensor_owner_id
              && (record_type_current == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
                  || record_type_current == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD))
            {
              uint8_t share_count;
              
	      if (record_type_current == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD)
		{
		  share_count = ptr[IPMI_SDR_RECORD_COMPACT_SHARE_COUNT];
		  share_count &= IPMI_SDR_RECORD_COMPACT_SHARE_COUNT_BITMASK;
		  share_count >>= IPMI_SDR_RECORD_COMPACT_SHARE_COUNT_SHIFT;
		}
	      else
		{
int
ipmi_sdr_cache_open (ipmi_sdr_ctx_t ctx,
                     ipmi_ctx_t ipmi_ctx,
                     const char *filename)
{
  uint8_t sdr_version;
  uint16_t record_count;
  uint32_t most_recent_addition_timestamp, most_recent_erase_timestamp;
  char sdr_version_buf;
  char sdr_cache_magic_buf[4];
  char sdr_cache_version_buf[4];
  char record_count_buf[2];
  char most_recent_addition_timestamp_buf[4];
  char most_recent_erase_timestamp_buf[4];
  struct stat stat_buf;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (!filename)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_UNINITIALIZED)
    {
      if (ctx->operation == IPMI_SDR_OPERATION_READ_CACHE)
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_ALREADY_INITIALIZED);
      else
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (stat (filename, &stat_buf) < 0)
    {
      SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
      goto cleanup;
    }

  /* File Size must be atleast magic_buf + file_version_buf +
   * sdr_version_buf + record_count_buf +
   * most_recent_addition_timestamp_buf +
   * most_recent_erase_timestamp-buf in size.
   */

  ctx->file_size = stat_buf.st_size;
  if (ctx->file_size < (4 + 4 + 1 + 2 + 4 + 4))
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
      goto cleanup;
    }

  if ((ctx->fd = open (filename, O_RDONLY)) < 0)
    {
      SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
      goto cleanup;
    }

  ctx->sdr_cache = (uint8_t *)mmap (NULL,
                                    ctx->file_size,
                                    PROT_READ,
                                    MAP_PRIVATE,
                                    ctx->fd,
                                    0);
  if (!ctx->sdr_cache || ctx->sdr_cache == ((void *) -1))
    {
      ERRNO_TRACE (errno);
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
      goto cleanup;
    }

  memcpy (sdr_cache_magic_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
  ctx->records_start_offset += 4;
  memcpy (sdr_cache_version_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
  ctx->records_start_offset += 4;
  memcpy (&sdr_version_buf, ctx->sdr_cache + ctx->records_start_offset, 1);
  ctx->records_start_offset += 1;
  memcpy (record_count_buf, ctx->sdr_cache + ctx->records_start_offset, 2);
  ctx->records_start_offset += 2;
  memcpy (most_recent_addition_timestamp_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
  ctx->records_start_offset += 4;
  memcpy (most_recent_erase_timestamp_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
  ctx->records_start_offset += 4;

  if ((uint8_t)sdr_cache_magic_buf[0] != IPMI_SDR_CACHE_FILE_MAGIC_0
      || (uint8_t)sdr_cache_magic_buf[1] != IPMI_SDR_CACHE_FILE_MAGIC_1
      || (uint8_t)sdr_cache_magic_buf[2] != IPMI_SDR_CACHE_FILE_MAGIC_2
      || (uint8_t)sdr_cache_magic_buf[3] != IPMI_SDR_CACHE_FILE_MAGIC_3)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
      goto cleanup;
    }

  if (((uint8_t)sdr_cache_version_buf[0] != IPMI_SDR_CACHE_FILE_VERSION_1_0
       || (uint8_t)sdr_cache_version_buf[1] != IPMI_SDR_CACHE_FILE_VERSION_1_1
       || (uint8_t)sdr_cache_version_buf[2] != IPMI_SDR_CACHE_FILE_VERSION_1_2
       || (uint8_t)sdr_cache_version_buf[3] != IPMI_SDR_CACHE_FILE_VERSION_1_3)
      && ((uint8_t)sdr_cache_version_buf[0] != IPMI_SDR_CACHE_FILE_VERSION_1_2_0
	  || (uint8_t)sdr_cache_version_buf[1] != IPMI_SDR_CACHE_FILE_VERSION_1_2_1
	  || (uint8_t)sdr_cache_version_buf[2] != IPMI_SDR_CACHE_FILE_VERSION_1_2_2
	  || (uint8_t)sdr_cache_version_buf[3] != IPMI_SDR_CACHE_FILE_VERSION_1_2_3))
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
      goto cleanup;
    }

  ctx->sdr_version = (uint8_t)sdr_version_buf;
  ctx->record_count = ((uint16_t)record_count_buf[0] & 0xFF);
  ctx->record_count |= ((uint16_t)record_count_buf[1] & 0xFF) << 8;
  ctx->most_recent_addition_timestamp = ((uint32_t)most_recent_addition_timestamp_buf[0] & 0xFF);
  ctx->most_recent_addition_timestamp |= ((uint32_t)most_recent_addition_timestamp_buf[1] & 0xFF) << 8;
  ctx->most_recent_addition_timestamp |= ((uint32_t)most_recent_addition_timestamp_buf[2] & 0xFF) << 16;
  ctx->most_recent_addition_timestamp |= ((uint32_t)most_recent_addition_timestamp_buf[3] & 0xFF) << 24;
  ctx->most_recent_erase_timestamp = ((uint32_t)most_recent_erase_timestamp_buf[0] & 0xFF);
  ctx->most_recent_erase_timestamp |= ((uint32_t)most_recent_erase_timestamp_buf[1] & 0xFF) << 8;
  ctx->most_recent_erase_timestamp |= ((uint32_t)most_recent_erase_timestamp_buf[2] & 0xFF) << 16;
  ctx->most_recent_erase_timestamp |= ((uint32_t)most_recent_erase_timestamp_buf[3] & 0xFF) << 24;

  if (ipmi_ctx)
    {
      if (sdr_info (ctx,
		    ipmi_ctx,
		    &sdr_version,
		    &record_count,
		    &most_recent_addition_timestamp,
		    &most_recent_erase_timestamp) < 0)
	goto cleanup;

      if (ctx->sdr_version != sdr_version
	  || ctx->most_recent_addition_timestamp != most_recent_addition_timestamp
	  || ctx->most_recent_erase_timestamp != most_recent_erase_timestamp)
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_OUT_OF_DATE);
	  goto cleanup;
	}
    }

  if ((uint8_t)sdr_cache_version_buf[0] == IPMI_SDR_CACHE_FILE_VERSION_1_2_0
      && (uint8_t)sdr_cache_version_buf[1] == IPMI_SDR_CACHE_FILE_VERSION_1_2_1
      && (uint8_t)sdr_cache_version_buf[2] == IPMI_SDR_CACHE_FILE_VERSION_1_2_2
      && (uint8_t)sdr_cache_version_buf[3] == IPMI_SDR_CACHE_FILE_VERSION_1_2_3)
    {
      uint8_t header_checksum_buf[512];
      unsigned int header_checksum_buf_len = 0;
      uint8_t header_checksum, header_checksum_cache;
      uint8_t trailer_checksum, trailer_checksum_cache;
      char total_bytes_written_buf[4];
      unsigned int total_bytes_written;
      unsigned int header_bytes_len;
      unsigned int trailer_bytes_len;

      /* File Size must be atleast magic_buf + file_version_buf +
       * sdr_version_buf + record_count_buf +
       * most_recent_addition_timestamp_buf +
       * most_recent_erase_timestamp-buf + header_checksum + trailer
       * bytes written + trailer records checksum.
       */
      
      header_bytes_len = 4 + 4 + 1 + 2 + 4 + 4 + 1;
      trailer_bytes_len = 4 + 1;

      if (ctx->file_size < (header_bytes_len + trailer_bytes_len))
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
	  goto cleanup;
	}

      memcpy (&header_checksum_cache, ctx->sdr_cache + ctx->records_start_offset, 1);
      ctx->records_start_offset += 1;

      memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_magic_buf, 4);
      header_checksum_buf_len += 4;
      memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_version_buf, 4);
      header_checksum_buf_len += 4;
      memcpy(&header_checksum_buf[header_checksum_buf_len], &sdr_version_buf, 1);
      header_checksum_buf_len += 1;
      memcpy(&header_checksum_buf[header_checksum_buf_len], record_count_buf, 2);
      header_checksum_buf_len += 2;
      memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_addition_timestamp_buf, 4);
      header_checksum_buf_len += 4;
      memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_erase_timestamp_buf, 4);
      header_checksum_buf_len += 4;
      
      header_checksum = ipmi_checksum (header_checksum_buf, header_checksum_buf_len);
      if (header_checksum != header_checksum_cache)
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
	  goto cleanup;
	}

      /* total_bytes_written is written before checksum */
      /* checksum of records is last byte written */
      memcpy (total_bytes_written_buf, ctx->sdr_cache + ctx->file_size - 5, 4);
      memcpy (&trailer_checksum_cache, ctx->sdr_cache + ctx->file_size - 1, 1);

      total_bytes_written = ((uint32_t)total_bytes_written_buf[0] & 0xFF);
      total_bytes_written |= ((uint32_t)total_bytes_written_buf[1] & 0xFF) << 8;
      total_bytes_written |= ((uint32_t)total_bytes_written_buf[2] & 0xFF) << 16;
      total_bytes_written |= ((uint32_t)total_bytes_written_buf[3] & 0xFF) << 24;

      if (total_bytes_written != ctx->file_size)
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
	  goto cleanup;
	}

      /* -1 for checksum */
      trailer_checksum = ipmi_checksum (ctx->sdr_cache + ctx->records_start_offset,
					total_bytes_written - ctx->records_start_offset - 1);

      if (trailer_checksum != trailer_checksum_cache)
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
	  goto cleanup;
	}

      ctx->records_end_offset = ctx->file_size - trailer_bytes_len;
    }
  else /* (uint8_t)sdr_cache_version_buf[0] == IPMI_SDR_CACHE_FILE_VERSION_1_0
	  && (uint8_t)sdr_cache_version_buf[1] == IPMI_SDR_CACHE_FILE_VERSION_1_1
	  && (uint8_t)sdr_cache_version_buf[2] == IPMI_SDR_CACHE_FILE_VERSION_1_2
	  && (uint8_t)sdr_cache_version_buf[3] == IPMI_SDR_CACHE_FILE_VERSION_1_3 */
    ctx->records_end_offset = ctx->file_size;

  _sdr_set_current_offset (ctx, ctx->records_start_offset);
  ctx->operation = IPMI_SDR_OPERATION_READ_CACHE;
  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (0);

 cleanup:
  /* ignore potential error, cleanup path */
  if (ctx->fd >= 0)
    close (ctx->fd);
  /* ignore potential error, cleanup path */
  if (ctx->sdr_cache)
    munmap ((void *)ctx->sdr_cache, ctx->file_size);
  sdr_init_ctx (ctx);
  return (-1);
}
/* return (1) - is oem intel node manager, fully parsed                                                                                     
 * return (0) - is not oem intel node manager                                                                                               
 * return (-1) - error                                                                                                                      
 */
int
ipmi_sdr_oem_parse_intel_node_manager (ipmi_sdr_ctx_t ctx,
                                       const void *sdr_record,
                                       unsigned int sdr_record_len,
                                       uint8_t *nm_device_slave_address,
                                       uint8_t *sensor_owner_lun,
                                       uint8_t *channel_number,
                                       uint8_t *nm_health_event_sensor_number,
                                       uint8_t *nm_exception_event_sensor_number,
                                       uint8_t *nm_operational_capabilities_sensor_number,
                                       uint8_t *nm_alert_threshold_exceeded_sensor_number)
{
  uint8_t sdr_record_buf[IPMI_SDR_MAX_RECORD_LENGTH];
  int sdr_record_buf_len;
  fiid_obj_t obj_oem_record = NULL;
  int expected_record_len;
  void *sdr_record_to_use;
  unsigned int sdr_record_len_to_use;
  uint64_t val;
  int rv = -1;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (!sdr_record || !sdr_record_len)
    {
      if (ctx->operation == IPMI_SDR_OPERATION_READ_CACHE
          && !sdr_record
          && !sdr_record_len)
        {
          if ((sdr_record_buf_len = ipmi_sdr_cache_record_read (ctx,
                                                                sdr_record_buf,
                                                                IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
            {
              SDR_SET_INTERNAL_ERRNUM (ctx);
              return (-1);
            }
          sdr_record_to_use = sdr_record_buf;
          sdr_record_len_to_use = sdr_record_buf_len;
        }
      else
        {
          SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
          return (-1);
        }
    }
  else
    {
      sdr_record_to_use = (void *)sdr_record;
      sdr_record_len_to_use = sdr_record_len;
    }

  if ((expected_record_len = fiid_template_len_bytes (tmpl_sdr_oem_intel_node_manager_record)) < 0)
    {
      SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
      goto cleanup;
    }
  
  if (sdr_record_len_to_use < expected_record_len)
    {
      rv = 0;
      goto cleanup;
    }

  if (!(obj_oem_record = fiid_obj_create (tmpl_sdr_oem_intel_node_manager_record)))
    {
      SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
      goto cleanup;
    }

  if (fiid_obj_set_all (obj_oem_record,
                        sdr_record_to_use,
                        expected_record_len) < 0)
    {
      SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
      goto cleanup;
    }

  /* achu: Node Manager documentation states that OEM ID in the
   * SDR record should be Intel's, but I've seen motherboards w/o
   * it, so don't bother checking.
   */

  if (FIID_OBJ_GET (obj_oem_record,
                    "record_subtype",
                    &val) < 0)
    {
      SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
      goto cleanup;
    }
  
  if (val != IPMI_SDR_OEM_INTEL_NODE_MANAGER_RECORD_SUBTYPE_NM_DISCOVERY)
    {
      rv = 0;
      goto cleanup;
    }

  if (FIID_OBJ_GET (obj_oem_record,
                    "version_number",
                    &val) < 0)
    {
      SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
      goto cleanup;
    }

  if (val != IPMI_SDR_OEM_INTEL_NODE_MANAGER_DISCOVERY_VERSION)
    {
      rv = 0;
      goto cleanup;
    }
     
  if (nm_device_slave_address)
    {
      if (FIID_OBJ_GET (obj_oem_record,
                        "nm_device_slave_address",
                        &val) < 0)
        {
          SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
          goto cleanup;
        }
      (*nm_device_slave_address) = val;
    }

  if (sensor_owner_lun)
    {
      if (FIID_OBJ_GET (obj_oem_record,
                        "sensor_owner_lun",
                        &val) < 0)
        {
          SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
          goto cleanup;
        }
      (*sensor_owner_lun) = val;
    }

  if (channel_number)
    {
      if (FIID_OBJ_GET (obj_oem_record,
                        "channel_number",
                        &val) < 0)
        {
          SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
          goto cleanup;
        }
      (*channel_number) = val;
    }

  if (nm_health_event_sensor_number)
    {
      if (FIID_OBJ_GET (obj_oem_record,
                        "nm_health_event_sensor_number",
                        &val) < 0)
        {
          SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
          goto cleanup;
        }
      (*nm_health_event_sensor_number) = val;
    }

  if (nm_exception_event_sensor_number)
    {
      if (FIID_OBJ_GET (obj_oem_record,
                        "nm_exception_event_sensor_number",
                        &val) < 0)
        {
          SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
          goto cleanup;
        }
      (*nm_exception_event_sensor_number) = val;
    }

  if (nm_operational_capabilities_sensor_number)
    {
      if (FIID_OBJ_GET (obj_oem_record,
                        "nm_operational_capabilities_sensor_number",
                        &val) < 0)
        {
          SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
          goto cleanup;
        }
      (*nm_operational_capabilities_sensor_number) = val;
    }
  
  if (nm_alert_threshold_exceeded_sensor_number)
    {
      if (FIID_OBJ_GET (obj_oem_record,
                        "nm_alert_threshold_exceeded_sensor_number",
                        &val) < 0)
        {
          SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record);
          goto cleanup;
        }
      (*nm_alert_threshold_exceeded_sensor_number) = val;
    }

  sdr_check_read_status (ctx);

  rv = 1;
  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_oem_record);
  return (rv);
}