/*
* Copyright (C) 2008-2015 FreeIPMI Core Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include
#include
#if STDC_HEADERS
#include
#endif /* STDC_HEADERS */
#include
#include
#include
#include "ipmi-oem.h"
#include "ipmi-oem-argp.h"
#include "ipmi-oem-common.h"
#include "freeipmi-portability.h"
#include "pstdout.h"
int
ipmi_oem_check_response_and_completion_code (ipmi_oem_state_data_t *state_data,
const void *bytes_rs,
unsigned int bytes_rs_len,
unsigned int expected_bytes_rs_len,
uint8_t cmd,
uint8_t netfn,
Ipmi_oem_comp_code_strerror comp_code_strerror)
{
const uint8_t *bytes_rs_ptr = bytes_rs;
assert (state_data);
assert (bytes_rs);
if (bytes_rs_len < expected_bytes_rs_len)
{
if (bytes_rs_len >= 2 && bytes_rs_ptr[1] != IPMI_COMP_CODE_COMMAND_SUCCESS)
goto output_comp_code_error;
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid response length: %u, expected %u\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
bytes_rs_len,
expected_bytes_rs_len);
return (-1);
}
output_comp_code_error:
if (bytes_rs_ptr[1] != IPMI_COMP_CODE_COMMAND_SUCCESS)
{
char errbuf[IPMI_OEM_ERR_BUFLEN + 1];
memset (errbuf, '\0', IPMI_OEM_ERR_BUFLEN + 1);
if (comp_code_strerror)
{
int ret;
if ((ret = comp_code_strerror (state_data,
bytes_rs_ptr[1], /* completion code */
cmd,
netfn,
errbuf,
IPMI_OEM_ERR_BUFLEN)) < 0)
snprintf (errbuf, IPMI_OEM_ERR_BUFLEN, "completion-code = 0x%X", bytes_rs_ptr[1]);
if (!ret)
goto standard_output_comp_code_error;
}
else
{
standard_output_comp_code_error:
if (ipmi_completion_code_strerror_r (cmd, /* cmd */
netfn, /* network function */
bytes_rs_ptr[1], /* completion code */
errbuf,
IPMI_OEM_ERR_BUFLEN) < 0)
{
#if 0
pstdout_perror (state_data->pstate, "ipmi_completion_code_strerror_r");
#endif
snprintf (errbuf, IPMI_OEM_ERR_BUFLEN, "completion-code = 0x%X", bytes_rs_ptr[1]);
}
}
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s failed: %s\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
errbuf);
return (-1);
}
return (0);
}
int
ipmi_oem_parse_key_value (ipmi_oem_state_data_t *state_data,
unsigned int option_num,
char **key,
char **value)
{
char *tempstr = NULL;
char *tempptr = NULL;
char *tempkey = NULL;
char *tempvalue = NULL;
int rv = -1;
assert (state_data);
assert (key);
assert (value);
if (!(tempstr = strdup (state_data->prog_data->args->oem_options[option_num])))
{
pstdout_perror (state_data->pstate, "strdup");
goto cleanup;
}
tempptr = strchr (tempstr, '=');
if (!tempptr)
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid OEM option argument '%s' : no equal sign\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
goto cleanup;
}
(*tempptr) = '\0';
tempptr++;
if (!(tempkey = strdup (tempstr)))
{
pstdout_perror (state_data->pstate, "strdup");
goto cleanup;
}
if (!(tempvalue = strdup (tempptr)))
{
pstdout_perror (state_data->pstate, "strdup");
goto cleanup;
}
(*key) = tempkey;
(*value) = tempvalue;
rv = 0;
cleanup:
free (tempstr);
if (rv < 0)
{
free (tempkey);
free (tempvalue);
}
return (rv);
}
int
ipmi_oem_parse_enable (ipmi_oem_state_data_t *state_data,
unsigned int option_num,
const char *value,
uint8_t *enable)
{
assert (state_data);
assert (value);
assert (enable);
if (strcasecmp (value, "enable") && strcasecmp (value, "disable"))
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid OEM option argument '%s' : invalid value\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
return (-1);
}
if (!strcasecmp (value, "enable"))
(*enable) = 1;
else
(*enable) = 0;
return (0);
}
int
ipmi_oem_parse_1_byte_field (ipmi_oem_state_data_t *state_data,
unsigned int option_num,
const char *value,
uint8_t *value_out)
{
unsigned int temp;
char *ptr = NULL;
assert (state_data);
assert (value);
assert (value_out);
errno = 0;
temp = strtoul (value, &ptr, 10);
if (errno
|| ptr[0] != '\0'
|| temp > UCHAR_MAX)
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid OEM option argument '%s' : invalid value\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
return (-1);
}
(*value_out) = temp;
return (0);
}
int
ipmi_oem_parse_2_byte_field (ipmi_oem_state_data_t *state_data,
unsigned int option_num,
const char *value,
uint16_t *value_out)
{
unsigned int temp;
char *ptr = NULL;
assert (state_data);
assert (value);
assert (value_out);
errno = 0;
temp = strtoul (value, &ptr, 10);
if (errno
|| ptr[0] != '\0'
|| temp > USHRT_MAX)
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid OEM option argument '%s' : invalid value\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
return (-1);
}
(*value_out) = temp;
return (0);
}
int
ipmi_oem_parse_4_byte_field (ipmi_oem_state_data_t *state_data,
unsigned int option_num,
const char *value,
uint32_t *value_out)
{
unsigned int temp;
char *ptr = NULL;
assert (state_data);
assert (value);
assert (value_out);
errno = 0;
temp = strtoul (value, &ptr, 10);
if (errno
|| ptr[0] != '\0')
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid OEM option argument '%s' : invalid value\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
return (-1);
}
(*value_out) = temp;
return (0);
}
int
ipmi_oem_parse_unsigned_int_range (ipmi_oem_state_data_t *state_data,
unsigned int option_num,
const char *value,
uint32_t *value_out,
unsigned int min,
unsigned int max)
{
unsigned int temp;
char *ptr = NULL;
assert (state_data);
assert (value);
assert (value_out);
assert (min < max);
errno = 0;
temp = strtoul (value, &ptr, 10);
if (errno
|| ptr[0] != '\0')
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid OEM option argument '%s' : invalid value\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
return (-1);
}
if (temp < min
|| temp > max)
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid OEM option argument '%s' : out of range\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
return (-1);
}
(*value_out) = temp;
return (0);
}
int
ipmi_oem_parse_ip_address (ipmi_oem_state_data_t *state_data,
unsigned int option_num,
const char *value,
uint32_t *ip_address)
{
unsigned int b1, b2, b3, b4;
uint32_t temp;
int ret;
assert (state_data);
assert (value);
assert (ip_address);
if ((ret = sscanf (value,
"%u.%u.%u.%u",
&b1,
&b2,
&b3,
&b4)) < 0)
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid IP address '%s'\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
return (-1);
}
if (ret != 4)
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid IP address '%s'\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
return (-1);
}
temp = 0;
temp |= (uint32_t)b1;
temp |= ((uint32_t)b2 << 8);
temp |= ((uint32_t)b3 << 16);
temp |= ((uint32_t)b4 << 24);
(*ip_address) = temp;
return (0);
}
int
ipmi_oem_parse_string (ipmi_oem_state_data_t *state_data,
unsigned int option_num,
const char *value,
uint8_t *string_length,
char *stringbuf,
unsigned int stringbuflen)
{
assert (state_data);
assert (value);
assert (string_length);
assert (stringbuf);
assert (stringbuflen);
if (strlen (value) > stringbuflen)
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s invalid OEM option argument '%s' : string length too long\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[option_num]);
return (-1);
}
(*string_length) = strlen (value);
/* use memcpy, do not need NULL termination */
if ((*string_length))
memcpy (stringbuf,
value,
(*string_length));
return (0);
}
int
ipmi_oem_get_system_info_string (ipmi_oem_state_data_t *state_data,
uint8_t parameter_selector,
uint8_t set_selector,
uint8_t block_selector,
char *string,
unsigned int string_len,
unsigned int *string_len_ret)
{
fiid_obj_t obj_cmd_rs = NULL;
uint8_t configuration_parameter_data[IPMI_OEM_MAX_BYTES];
int len;
int rv = -1;
assert (state_data);
assert (string);
assert (string_len);
if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_system_info_parameters_rs)))
{
pstdout_fprintf (state_data->pstate,
stderr,
"fiid_obj_create: %s\n",
strerror (errno));
goto cleanup;
}
if (ipmi_cmd_get_system_info_parameters (state_data->ipmi_ctx,
IPMI_GET_SYSTEM_INFO_PARAMETER,
parameter_selector,
set_selector,
block_selector,
obj_cmd_rs) < 0)
{
if ((ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
&& ipmi_check_completion_code (obj_cmd_rs,
IPMI_COMP_CODE_GET_SYSTEM_INFO_PARAMETERS_PARAMETER_NOT_SUPPORTED) == 1)
|| (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_COMMAND_INVALID_OR_UNSUPPORTED
&& ipmi_check_completion_code (obj_cmd_rs,
IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1))
{
pstdout_fprintf (state_data->pstate,
stderr,
"%s:%s '%s' option not supported on this system\n",
state_data->prog_data->args->oem_id,
state_data->prog_data->args->oem_command,
state_data->prog_data->args->oem_options[0]);
goto cleanup;
}
pstdout_fprintf (state_data->pstate,
stderr,
"ipmi_cmd_get_system_info_parameters: %s\n",
ipmi_ctx_errormsg (state_data->ipmi_ctx));
goto cleanup;
}
if ((len = fiid_obj_get_data (obj_cmd_rs,
"configuration_parameter_data",
configuration_parameter_data,
IPMI_OEM_MAX_BYTES)) < 0)
{
pstdout_fprintf (state_data->pstate,
stderr,
"fiid_obj_get_data: 'configuration_parameter_data': %s\n",
fiid_obj_errormsg (obj_cmd_rs));
goto cleanup;
}
if (len > string_len)
{
pstdout_fprintf (state_data->pstate,
stderr,
"buffer overflow\n");
goto cleanup;
}
memcpy (string,
&(configuration_parameter_data[0]),
len);
if (string_len_ret)
(*string_len_ret) = len;
rv = 0;
cleanup:
fiid_obj_destroy (obj_cmd_rs);
return (rv);
}