Imported Upstream version 2.7.1

This commit is contained in:
Laurent Bigonville 2013-11-24 16:00:12 +01:00
parent a1fa151fc7
commit 0121794af9
451 changed files with 41339 additions and 10887 deletions

View file

@ -29,6 +29,8 @@
*
*/
#include <limits.h>
/* NUT SNMP common functions */
#include "main.h"
#include "snmp-ups.h"
@ -45,6 +47,7 @@
#include "compaq-mib.h"
#include "bestpower-mib.h"
#include "cyberpower-mib.h"
#include "delta_ups-mib.h"
#include "ietf-mib.h"
/* Address API change */
@ -67,6 +70,7 @@ static mib2nut_info_t *mib2nut[] = {
&compaq,
&bestpower,
&cyberpower,
&delta_ups,
/*
* Prepend vendor specific MIB mappings before IETF, so that
* if a device supports both IETF and vendor specific MIB,
@ -87,13 +91,14 @@ int input_phases, output_phases, bypass_phases;
mib2nut_info_t *mib2nut_info;
/* FIXME: to be trashed */
snmp_info_t *snmp_info;
alarms_info_t *alarms_info;
const char *mibname;
const char *mibvers;
static void disable_transfer_oids(void);
#define DRIVER_NAME "Generic SNMP UPS driver"
#define DRIVER_VERSION "0.68"
#define DRIVER_VERSION "0.70"
/* driver description structure */
upsdrv_info_t upsdrv_info = {
@ -469,77 +474,139 @@ void nut_snmp_cleanup(void)
SOCK_CLEANUP; /* wrapper not needed on Unix! */
}
struct snmp_pdu *nut_snmp_get(const char *OID)
/* Free a struct snmp_pdu * returned by nut_snmp_walk */
void nut_snmp_free(struct snmp_pdu ** array_to_free)
{
struct snmp_pdu ** current_element;
current_element = array_to_free;
while (*current_element != NULL) {
snmp_free_pdu(*current_element);
current_element++;
}
free( array_to_free );
}
/* Return a NULL terminated array of snmp_pdu * */
struct snmp_pdu **nut_snmp_walk(const char *OID, int max_iteration)
{
int status;
struct snmp_pdu *pdu, *response = NULL;
oid name[MAX_OID_LEN];
size_t name_len = MAX_OID_LEN;
oid * current_name;
size_t current_name_len;
static unsigned int numerr = 0;
int nb_iteration = 0;
struct snmp_pdu ** ret_array = NULL;
int type = SNMP_MSG_GET;
upsdebugx(3, "nut_snmp_get(%s)", OID);
upsdebugx(3, "nut_snmp_walk(%s)", OID);
/* create and send request. */
if (!snmp_parse_oid(OID, name, &name_len)) {
upsdebugx(2, "[%s] nut_snmp_get: %s: %s",
upsdebugx(2, "[%s] nut_snmp_walk: %s: %s",
upsname?upsname:device_name, OID, snmp_api_errstring(snmp_errno));
return NULL;
}
pdu = snmp_pdu_create(SNMP_MSG_GET);
current_name = name;
current_name_len = name_len;
if (pdu == NULL)
fatalx(EXIT_FAILURE, "Not enough memory");
snmp_add_null_var(pdu, name, name_len);
status = snmp_synch_response(g_snmp_sess_p, pdu, &response);
if (!response)
return NULL;
if (!((status == STAT_SUCCESS) && (response->errstat == SNMP_ERR_NOERROR)))
{
if (mibname == NULL) {
/* We are probing for proper mib - ignore errors */
snmp_free_pdu(response);
return NULL;
while( nb_iteration < max_iteration ) {
/* Going to a shorter OID means we are outside our sub-tree */
if( current_name_len < name_len ) {
break;
}
numerr++;
pdu = snmp_pdu_create(type);
if ((numerr == SU_ERR_LIMIT) || ((numerr % SU_ERR_RATE) == 0))
upslogx(LOG_WARNING, "[%s] Warning: excessive poll "
"failures, limiting error reporting",
upsname?upsname:device_name);
if (pdu == NULL) {
fatalx(EXIT_FAILURE, "Not enough memory");
}
if ((numerr < SU_ERR_LIMIT) || ((numerr % SU_ERR_RATE) == 0))
nut_snmp_perror(g_snmp_sess_p, status, response,
"nut_snmp_get: %s", OID);
snmp_add_null_var(pdu, current_name, current_name_len);
snmp_free_pdu(response);
response = NULL;
} else {
numerr = 0;
status = snmp_synch_response(g_snmp_sess_p, pdu, &response);
if (!response) {
break;
}
if (!((status == STAT_SUCCESS) && (response->errstat == SNMP_ERR_NOERROR))) {
if (mibname == NULL) {
/* We are probing for proper mib - ignore errors */
snmp_free_pdu(response);
return NULL;
}
numerr++;
if ((numerr == SU_ERR_LIMIT) || ((numerr % SU_ERR_RATE) == 0)) {
upslogx(LOG_WARNING, "[%s] Warning: excessive poll "
"failures, limiting error reporting",
upsname?upsname:device_name);
}
if ((numerr < SU_ERR_LIMIT) || ((numerr % SU_ERR_RATE) == 0)) {
if (type == SNMP_MSG_GETNEXT) {
upsdebugx(2, "=> No more OID, walk complete");
}
else {
nut_snmp_perror(g_snmp_sess_p, status, response,
"nut_snmp_walk: %s", OID);
}
}
snmp_free_pdu(response);
break;
} else {
numerr = 0;
}
nb_iteration++;
/* +1 is for the terminating NULL */
ret_array = realloc(ret_array,sizeof(struct snmp_pdu*)*(nb_iteration+1));
ret_array[nb_iteration-1] = response;
ret_array[nb_iteration]=NULL;
current_name = response->variables->name;
current_name_len = response->variables->name_length;
type = SNMP_MSG_GETNEXT;
}
return response;
return ret_array;
}
bool_t nut_snmp_get_str(const char *OID, char *buf, size_t buf_len, info_lkp_t *oid2info)
struct snmp_pdu *nut_snmp_get(const char *OID)
{
size_t len = 0;
struct snmp_pdu *pdu;
struct snmp_pdu ** pdu_array;
struct snmp_pdu * ret_pdu;
upsdebugx(3, "Entering nut_snmp_get_str()");
upsdebugx(3, "nut_snmp_get(%s)", OID);
pdu_array = nut_snmp_walk(OID,1);
if(pdu_array == NULL) {
return NULL;
}
ret_pdu = snmp_clone_pdu(*pdu_array);
nut_snmp_free(pdu_array);
return ret_pdu;
}
static bool_t decode_str(struct snmp_pdu *pdu, char *buf, size_t buf_len, info_lkp_t *oid2info) {
size_t len = 0;
/* zero out buffer. */
memset(buf, 0, buf_len);
pdu = nut_snmp_get(OID);
if (pdu == NULL)
return FALSE;
switch (pdu->variables->type) {
case ASN_OCTET_STR:
case ASN_OPAQUE:
@ -573,14 +640,33 @@ bool_t nut_snmp_get_str(const char *OID, char *buf, size_t buf_len, info_lkp_t *
len = snprint_objid (buf, buf_len, pdu->variables->val.objid, pdu->variables->val_len / sizeof(oid));
break;
default:
return FALSE;
}
return TRUE;
}
bool_t nut_snmp_get_str(const char *OID, char *buf, size_t buf_len, info_lkp_t *oid2info)
{
struct snmp_pdu *pdu;
bool_t ret;
upsdebugx(3, "Entering nut_snmp_get_str()");
pdu = nut_snmp_get(OID);
if (pdu == NULL)
return FALSE;
ret = decode_str(pdu,buf,buf_len,oid2info);
if(ret == FALSE) {
upsdebugx(2, "[%s] unhandled ASN 0x%x received from %s",
upsname?upsname:device_name, pdu->variables->type, OID);
return FALSE;
}
snmp_free_pdu(pdu);
return TRUE;
return ret;
}
bool_t nut_snmp_get_int(const char *OID, long *pval)
@ -917,6 +1003,7 @@ bool_t load_mib2nut(const char *mib)
OID_pwr_status = m2n->oid_pwr_status;
mibname = m2n->mib_name;
mibvers = m2n->mib_version;
alarms_info = m2n->alarms_info;
upsdebugx(1, "load_mib2nut: using %s mib", mibname);
return TRUE;
}
@ -1276,50 +1363,56 @@ bool_t snmp_ups_walk(int mode)
outlet_count = atoi(dstate_getinfo("outlet.count"));
}
/* general init of data using the template */
instantiate_info(su_info_p, &cur_info_p);
/* Only instantiate outlets if needed! */
if (outlet_count > 0) {
/* general init of data using the template */
instantiate_info(su_info_p, &cur_info_p);
for (cur_outlet_number = base_snmp_outlet_index(su_info_p->OID) ;
cur_outlet_number < (outlet_count + base_snmp_outlet_index(su_info_p->OID)) ;
cur_outlet_number++)
{
cur_nut_index = cur_outlet_number + base_nut_outlet_offset();
sprintf((char*)cur_info_p.info_type, su_info_p->info_type,
cur_nut_index);
for (cur_outlet_number = base_snmp_outlet_index(su_info_p->OID) ;
cur_outlet_number < (outlet_count + base_snmp_outlet_index(su_info_p->OID)) ;
cur_outlet_number++)
{
cur_nut_index = cur_outlet_number + base_nut_outlet_offset();
sprintf((char*)cur_info_p.info_type, su_info_p->info_type,
cur_nut_index);
/* check if default value is also a template */
if ((cur_info_p.dfl != NULL) &&
(strstr(su_info_p->dfl, "%i") != NULL)) {
cur_info_p.dfl = (char *)xmalloc(SU_INFOSIZE);
sprintf((char *)cur_info_p.dfl, su_info_p->dfl, cur_nut_index);
}
if (cur_info_p.OID != NULL) {
sprintf((char *)cur_info_p.OID, su_info_p->OID, cur_outlet_number);
/* add outlet instant commands to the info database. */
if (SU_TYPE(su_info_p) == SU_TYPE_CMD) {
/* FIXME: only add if "su_ups_get(cur_info_p) == TRUE" */
if (mode == SU_WALKMODE_INIT)
dstate_addcmd(cur_info_p.info_type);
/* check if default value is also a template */
if ((cur_info_p.dfl != NULL) &&
(strstr(su_info_p->dfl, "%i") != NULL)) {
cur_info_p.dfl = (char *)xmalloc(SU_INFOSIZE);
sprintf((char *)cur_info_p.dfl, su_info_p->dfl, cur_nut_index);
}
else /* get and process this data */
status = get_and_process_data(mode, &cur_info_p);
} else {
/* server side (ABSENT) data */
su_setinfo(&cur_info_p, NULL);
}
/* set back the flag */
su_info_p->flags = cur_info_p.flags;
}
free((char*)cur_info_p.info_type);
if (cur_info_p.OID != NULL)
free((char*)cur_info_p.OID);
if ((cur_info_p.dfl != NULL) &&
(strstr(su_info_p->dfl, "%i") != NULL))
free((char*)cur_info_p.dfl);
} else {
if (cur_info_p.OID != NULL) {
sprintf((char *)cur_info_p.OID, su_info_p->OID, cur_outlet_number);
/* add outlet instant commands to the info database. */
if (SU_TYPE(su_info_p) == SU_TYPE_CMD) {
/* FIXME: only add if "su_ups_get(cur_info_p) == TRUE" */
if (mode == SU_WALKMODE_INIT)
dstate_addcmd(cur_info_p.info_type);
}
else /* get and process this data */
status = get_and_process_data(mode, &cur_info_p);
} else {
/* server side (ABSENT) data */
su_setinfo(&cur_info_p, NULL);
}
/* set back the flag */
su_info_p->flags = cur_info_p.flags;
}
free((char*)cur_info_p.info_type);
if (cur_info_p.OID != NULL)
free((char*)cur_info_p.OID);
if ((cur_info_p.dfl != NULL) &&
(strstr(su_info_p->dfl, "%i") != NULL))
free((char*)cur_info_p.dfl);
}
else {
upsdebugx(1, "No outlet present, discarding template definition...");
}
}
else {
/* get and process this data */
status = get_and_process_data(mode, su_info_p);
}
@ -1335,6 +1428,10 @@ bool_t su_ups_get(snmp_info_t *su_info_p)
static char buf[SU_INFOSIZE];
bool_t status;
long value;
struct snmp_pdu ** pdu_array;
struct snmp_pdu * current_pdu;
alarms_info_t * alarms;
int index = 0;
upsdebugx(2, "su_ups_get: %s %s", su_info_p->info_type, su_info_p->OID);
@ -1351,6 +1448,43 @@ bool_t su_ups_get(snmp_info_t *su_info_p)
return status;
}
if (!strcasecmp(su_info_p->info_type, "ups.alarms")) {
status = nut_snmp_get_int(su_info_p->OID, &value);
if (status == TRUE) {
upsdebugx(2, "=> value: %ld", value);
if( value > 0 ) {
pdu_array = nut_snmp_walk(su_info_p->OID,INT_MAX);
if(pdu_array == NULL) {
upsdebugx(2, "=> Walk failed");
return FALSE;
}
current_pdu = pdu_array[index];
while(current_pdu) {
decode_str(current_pdu,buf,sizeof(buf),NULL);
alarms = alarms_info;
while( alarms->OID ) {
if(!strcmp(buf+1,alarms_info->OID)) {
upsdebugx(3, "Alarm OID %s found => %s", alarms->OID, alarms->info_value);
status_set(alarms->info_value);
break;
}
alarms++;
}
index++;
current_pdu = pdu_array[index];
}
nut_snmp_free(pdu_array);
}
}
else {
upsdebugx(2, "=> Failed");
}
return status;
}
/* another special case */
if (!strcasecmp(su_info_p->info_type, "ambient.temperature")) {
float temp=0;