/*
* Copyright (C) 2003-2015 FreeIPMI Core Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifdef HAVE_CONFIG_H
#include
#endif /* HAVE_CONFIG_H */
#include
#include
#ifdef STDC_HEADERS
#include
#include
#endif /* STDC_HEADERS */
#if HAVE_UNISTD_H
#include
#endif /* HAVE_UNISTD_H */
#include
#include
#include "freeipmi/debug/ipmi-debug.h"
#include "freeipmi/fiid/fiid.h"
#include "freeipmi/interface/ipmi-ipmb-interface.h"
#include "ipmi-debug-common.h"
#include "libcommon/ipmi-trace.h"
#include "freeipmi-portability.h"
#define IPMI_DEBUG_MAX_BUF_LEN 65536
#define IPMI_DEBUG_MAX_PKT_LEN 65536
#define IPMI_DEBUG_CHAR_PER_LINE 8
#define IPMI_DEBUG_DEFAULT_FD STDERR_FILENO
static int
_write (int fd, const void *buf, size_t n)
{
/* chu: by Chris Dunlap */
size_t nleft;
ssize_t nwritten;
unsigned char *p;
p = (unsigned char *)buf;
nleft = n;
while (nleft > 0)
{
if ((nwritten = write (fd, p, nleft)) < 0)
{
if (errno == EINTR)
continue;
else
return (-1);
}
nleft -= nwritten;
p += nwritten;
}
return (n);
}
int
debug_dprintf (int fd, const char *fmt, ...)
{
va_list ap;
int len, rv;
char buf[IPMI_DEBUG_MAX_BUF_LEN];
va_start (ap, fmt);
len = vsnprintf (buf, IPMI_DEBUG_MAX_BUF_LEN, fmt, ap);
rv = _write (fd, buf, len);
va_end (ap);
return (rv);
}
int
debug_set_prefix (char *buf, unsigned int buflen, const char *prefix)
{
assert (buf && buflen > 3);
/* clear buffer, empty prefix allowed */
memset (buf, '\0', buflen);
if (prefix)
{
strncpy (buf, prefix, buflen);
buf[buflen - 1] = '\0'; /* strncpy may not null terminate */
buf[buflen - 2] = '\0'; /* guaranteed space for ' ' */
buf[buflen - 3] = '\0'; /* guaranteed space for ':' */
strcat (buf, ": ");
}
return (0);
}
int
debug_output_str (int fd, const char *prefix, const char *str)
{
/* achu: Yeah, I know this is slow. Figure out something better
* later.
*/
if (str)
{
char *ptr = (char *)str;
if (prefix)
{
if (debug_dprintf (fd, "%s", prefix) < 0)
{
ERRNO_TRACE (errno);
return (-1);
}
}
while (*ptr != '\0')
{
if (*ptr == '\n')
{
if (debug_dprintf (fd, "%c", *ptr++) < 0)
{
ERRNO_TRACE (errno);
return (-1);
}
if (prefix)
{
if (debug_dprintf (fd, "%s", prefix) < 0)
{
ERRNO_TRACE (errno);
return (-1);
}
}
}
else
{
if (debug_dprintf (fd, "%c", *ptr++) < 0)
{
ERRNO_TRACE (errno);
return (-1);
}
}
}
if (debug_dprintf (fd, "\n") < 0)
{
ERRNO_TRACE (errno);
return (-1);
}
}
return (0);
}
int
debug_output_byte_array (int fd, const char *prefix, const uint8_t *buf, unsigned int buf_len)
{
unsigned int count = 0;
assert (buf);
while (count < buf_len)
{
int i = 0;
if (prefix)
{
if (debug_dprintf (fd, "%s", prefix) < 0)
{
ERRNO_TRACE (errno);
return (-1);
}
}
if (debug_dprintf (fd, "[ ") < 0)
{
ERRNO_TRACE (errno);
return (-1);
}
while (count < buf_len && i < IPMI_DEBUG_CHAR_PER_LINE)
{
if (debug_dprintf (fd, "%02Xh ", buf[count++]) < 0)
{
ERRNO_TRACE (errno);
return (-1);
}
i++;
}
if (debug_dprintf (fd, "]\n") < 0)
{
ERRNO_TRACE (errno);
return (-1);
}
}
return (0);
}
int
debug_dump_ipmb (int fd,
const char *prefix,
const uint8_t *ipmb_buf,
unsigned int ipmb_buf_len,
fiid_template_t tmpl_ipmb_msg_hdr,
fiid_template_t tmpl_ipmb_cmd)
{
char *ipmb_msg_hdr =
"IPMB Message Header:\n"
"--------------------";
char *ipmb_cmd_hdr =
"IPMB Message Data:\n"
"------------------";
char *ipmb_msg_trlr_hdr =
"IPMB Message Trailer:\n"
"---------------------";
char *ipmb_unexpected_hdr =
"IPMB Unexpected Data:\n"
"---------------------";
fiid_obj_t obj_ipmb_msg_hdr = NULL;
fiid_obj_t obj_ipmb_cmd = NULL;
fiid_obj_t obj_ipmb_msg_trlr = NULL;
fiid_obj_t obj_ipmb_unexpected_data = NULL;
int obj_ipmb_msg_trlr_len = 0;
unsigned int obj_ipmb_cmd_len = 0;
int ipmb_hdr_len = 0;
int ipmb_cmd_len = 0;
int ipmb_trlr_len = 0;
int len;
unsigned int ipmb_indx = 0;
int rv = -1;
assert (ipmb_buf);
assert (ipmb_buf_len);
assert (tmpl_ipmb_msg_hdr);
assert (tmpl_ipmb_cmd);
if (!(obj_ipmb_msg_hdr = fiid_obj_create (tmpl_ipmb_msg_hdr)))
{
ERRNO_TRACE (errno);
goto cleanup;
}
if (!(obj_ipmb_cmd = fiid_obj_create (tmpl_ipmb_cmd)))
{
ERRNO_TRACE (errno);
goto cleanup;
}
if (!(obj_ipmb_msg_trlr = fiid_obj_create (tmpl_ipmb_msg_trlr)))
{
ERRNO_TRACE (errno);
goto cleanup;
}
if ((obj_ipmb_msg_trlr_len = fiid_template_len_bytes (tmpl_ipmb_msg_trlr)) < 0)
{
ERRNO_TRACE (errno);
goto cleanup;
}
if ((ipmb_hdr_len = fiid_obj_set_all (obj_ipmb_msg_hdr,
ipmb_buf,
ipmb_buf_len)) < 0)
{
FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr);
goto cleanup;
}
ipmb_indx += ipmb_hdr_len;
if (ipmi_obj_dump (fd,
prefix,
ipmb_msg_hdr,
NULL,
obj_ipmb_msg_hdr) < 0)
{
ERRNO_TRACE (errno);
goto cleanup;
}
if (ipmb_buf_len <= ipmb_indx)
{
rv = 0;
goto cleanup;
}
if ((ipmb_buf_len - ipmb_hdr_len) <= obj_ipmb_msg_trlr_len)
goto dump_ipmb_extra;
obj_ipmb_cmd_len = (ipmb_buf_len - ipmb_hdr_len) - obj_ipmb_msg_trlr_len;
if ((ipmb_cmd_len = fiid_obj_set_all (obj_ipmb_cmd,
ipmb_buf + ipmb_hdr_len,
obj_ipmb_cmd_len)) < 0)
{
FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_cmd);
goto cleanup;
}
ipmb_indx += ipmb_cmd_len;
if (ipmi_obj_dump (fd,
prefix,
ipmb_cmd_hdr,
NULL,
obj_ipmb_cmd) < 0)
{
ERRNO_TRACE (errno);
goto cleanup;
}
if (ipmb_buf_len <= ipmb_indx)
{
rv = 0;
goto cleanup;
}
if ((ipmb_trlr_len = fiid_obj_set_all (obj_ipmb_msg_trlr,
ipmb_buf + ipmb_hdr_len + ipmb_cmd_len,
(ipmb_buf_len - ipmb_hdr_len - ipmb_cmd_len))) < 0)
{
FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_trlr);
goto cleanup;
}
ipmb_indx += ipmb_trlr_len;
if (ipmi_obj_dump (fd,
prefix,
ipmb_msg_trlr_hdr,
NULL,
obj_ipmb_msg_trlr) < 0)
{
ERRNO_TRACE (errno);
goto cleanup;
}
/* Dump IPMB unexpected stuff */
dump_ipmb_extra:
if ((ipmb_buf_len - ipmb_indx) > 0)
{
if (!(obj_ipmb_unexpected_data = fiid_obj_create (tmpl_unexpected_data)))
{
ERRNO_TRACE (errno);
goto cleanup;
}
if ((len = fiid_obj_set_all (obj_ipmb_unexpected_data,
ipmb_buf + ipmb_indx,
ipmb_buf_len - ipmb_indx)) < 0)
{
FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_unexpected_data);
goto cleanup;
}
ipmb_indx += len;
if (ipmi_obj_dump (fd,
prefix,
ipmb_unexpected_hdr,
NULL,
obj_ipmb_unexpected_data) < 0)
{
ERRNO_TRACE (errno);
goto cleanup;
}
}
rv = 0;
cleanup:
fiid_obj_destroy (obj_ipmb_msg_hdr);
fiid_obj_destroy (obj_ipmb_cmd);
fiid_obj_destroy (obj_ipmb_msg_trlr);
fiid_obj_destroy (obj_ipmb_unexpected_data);
return (rv);
}