Skip to content

Commit

Permalink
Merge pull request networkupstools#58 from jimklimov/DMF-integration
Browse files Browse the repository at this point in the history
DMF integration stage 5: API stabilized
  • Loading branch information
vyskocilm committed May 13, 2016
2 parents 2c6c6f9 + a479408 commit 53a9836
Show file tree
Hide file tree
Showing 7 changed files with 506 additions and 143 deletions.
32 changes: 32 additions & 0 deletions drivers/snmp-ups.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
#include "snmp-ups.h"
#include "parseconf.h"

#ifdef WITH_DMFMIB
#include "dmf.h"
#else
/* include all known mib2nut lookup tables */
#include "apc-mib.h"
#include "mge-mib.h"
Expand All @@ -56,12 +59,17 @@
#include "xppc-mib.h"
#include "eaton-ats-mib.h"
#include "apc-ats-mib.h"
#endif

/* Address API change */
#ifndef usmAESPrivProtocol
#define usmAESPrivProtocol usmAES128PrivProtocol
#endif

#ifdef WITH_DMFMIB
mib2nut_info_t *mib2nut = NULL;
mibdmf_parser_t *dmp = NULL;
#else
static mib2nut_info_t *mib2nut[] = {
&apc,
&mge,
Expand Down Expand Up @@ -94,6 +102,7 @@ static mib2nut_info_t *mib2nut[] = {
/* end of structure. */
NULL
};
#endif

struct snmp_session g_snmp_sess, *g_snmp_sess_p;
const char *OID_pwr_status;
Expand All @@ -109,7 +118,11 @@ alarms_info_t *alarms_info;
const char *mibname;
const char *mibvers;

#ifdef WITH_DMFMIB
#define DRIVER_NAME "Generic SNMP UPS driver (DMF)"
#else
#define DRIVER_NAME "Generic SNMP UPS driver"
#endif
#define DRIVER_VERSION "0.98"

/* driver description structure */
Expand Down Expand Up @@ -288,6 +301,22 @@ void upsdrv_initups(void)

upsdebugx(1, "SNMP UPS driver: entering %s()", __func__);

#ifdef WITH_DMFMIB
dmp = mibdmf_parser_new();
if (!dmp) {
upsdebugx(1,"FATAL: Can not allocate the DMF parsing structures");
return;
}
/* FIXME: Add configurability of where we look for *.dmf files */
mibdmf_parse_dir("/usr/share/nut/dmf/", dmp);
mib2nut = mibdmf_get_mib2nut_table(dmp);
if (!mib2nut)
{
upsdebugx(1,"FATAL: Can not access the mib2nut table parsed from DMF library");
return;
}
#endif

/* Retrieve user's parameters */
mibs = testvar(SU_VAR_MIBS) ? getval(SU_VAR_MIBS) : "auto";

Expand Down Expand Up @@ -341,6 +370,9 @@ void upsdrv_initups(void)
void upsdrv_cleanup(void)
{
nut_snmp_cleanup();
#ifdef WITH_DMFMIB
mibdmf_parser_destroy(&dmp);
#endif
}

/* -----------------------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions drivers/snmp-ups.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@
- rework the flagging system
*/

#ifndef SNMP_UPS_H
#define SNMP_UPS_H

#ifdef WITH_DMF_LUA
# include <lua.h>
# include <lauxlib.h>
# include <lualib.h>
#endif

#ifndef SNMP_UPS_H
#define SNMP_UPS_H

/* FIXME: still needed?
* workaround for buggy Net-SNMP config */
#ifdef PACKAGE_BUGREPORT
Expand Down
5 changes: 5 additions & 0 deletions scripts/DMF/README.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ code is provided to read the library of complete DMFs (and validate their
contents along the way), and produce a DMF file that only contains truncated
`mib2nut` entries as needed for the `nut-scanner`. This `dmf-reindex` program
is expected to become an end-user tool, to help during updates of the DMF set.
NOTE: In the current iteration the `dmf-reindex` program is not configurable,
so it just scans all `*.dmf*` files in the current directory and prints XML
DMF markup to `stdout` so you can redirect it to another file. To avoid later
duplicate entries, consider naming that file with a different extension (may
be uppercased `*.DMF` for example).

Overview of DMF usage from C code is maintained in the `dmf.h` file, driver
and application developers should look there for the "The big theory" details.
Expand Down
157 changes: 131 additions & 26 deletions scripts/DMF/dmf-reindex.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,58 +30,163 @@
int
main ()
{
int result = 0;
char *dir_name = "./"; // TODO: Make configurable the dir and/or list of files
// TODO: Usage (help), Command-line args
// option to append just a few (new) files to existing (large) index

alist_t * list = alist_new(
NULL,(void (*)(void **))alist_destroy, NULL );
if (!list) {
fprintf(stderr,"=== DMF-Reindex: FATAL: Can not allocate the auxiliary list\n");
mibdmf_parser_t * dmp = mibdmf_parser_new();
if (!dmp) {
fprintf(stderr,"=== DMF-Reindex: FATAL: Can not allocate the DMF parsing structures\n");
return ENOMEM;
}
dmf_parser_init();

fprintf(stderr, "=== DMF-Reindex: Loading DMF structures from directory '%s':\n\n",
dir_name);
parse_dir(dir_name, list);
result = mibdmf_parse_dir(dir_name, dmp);
// TODO: Error-checking? Faults in some parses should be fatal or not?

// Loop through discovered device_table and print it back as DMF markup
fprintf(stderr, "=== DMF-Reindex: Print DMF subset for snmp_device_table[]...\n\n");
snmp_device_id_t *devtab = get_device_table();
snmp_device_id_t *devtab = mibdmf_get_device_table(dmp);
if (!devtab)
{
fprintf(stderr,"=== DMF-Reindex: FATAL: Can not access the parsed device_table\n");
return ENOMEM;
}

// TODO: sprintf the index into a memory string, parse the result as a DMF
// with a new alist and tables (to validate) and test the same data is found.
// And only then output the stdout text.
// Needs fully dynamic alists (no global tables) and a version of parse_file
// for full in-memory strings.
// TODO: uniquify output, so that an index that was read in does not pollute?
// Below we sprintf the index into a memory string, parse the result as
// a DMF with a new alist and tables (to validate) and test the same data
// is found. And only then output the stdout text.
// TODO: uniquify output, so that an old index that was read in does not
// pollute the parsed results (at least not for completely same items as
// already exist in the table)? What to do about partial hits ~ updates?
size_t i;
printf("<nut>\n");
size_t newdmf_len=0, newdmf_size=1024;
char *newdmf = (char*)calloc(newdmf_size, sizeof(char));
if (!newdmf) {
fprintf(stderr,"=== DMF-Reindex: FATAL: Can not allocate the buffer for parsed DMF\n");
return ENOMEM;
}
newdmf_len += snprintf(newdmf + newdmf_len, (newdmf_size - newdmf_len), "<nut>\n");
for (i=0; devtab[i].oid != NULL || devtab[i].mib != NULL || devtab[i].sysoid != NULL ; i++)
{
//fprintf(stderr,"[%d] ",i);
//printf("[%d]\t<mib2nut ", i);
printf("\t<mib2nut ");
printf("auto_check=\"%s\" ", devtab[i].oid ? devtab[i].oid : ""); // [3 oid_auto_check] oid
if (devtab[i].mib != NULL) printf("mib_name=\"%s\" ", devtab[i].mib); // [0 mib_name] mib
if (devtab[i].sysoid != NULL) printf("oid=\"%s\" ", devtab[i].sysoid); // [5 sysOID] sysoid/NULL
printf("/>\n");
#ifdef DEBUG
fprintf(stderr,"[num=%zu (lenbefore=%zu)] ", i, newdmf_len);
#endif

// ASSUMPTION: String increments would not exceed these few bytes
if ( (newdmf_size - newdmf_len) < 256)
{
newdmf_size += 1024;
newdmf = (char*)realloc(newdmf, newdmf_size * sizeof(char));
if (!newdmf) {
fprintf(stderr,"=== DMF-Reindex: FATAL: Can not extend the buffer for parsed DMF\n");
return ENOMEM;
}
#ifdef DEBUG
fprintf(stderr, "\nExtended the buffer to %zu bytes\n", newdmf_size);
#endif
}

newdmf_len += snprintf(newdmf + newdmf_len, (newdmf_size - newdmf_len),
"\t<mib2nut ");

// This attr is always present, even if as an empty string:
newdmf_len += snprintf(newdmf + newdmf_len, (newdmf_size - newdmf_len),
"auto_check=\"%s\" ", devtab[i].oid ? devtab[i].oid : ""); // [3 oid_auto_check] oid

if (devtab[i].mib != NULL)
newdmf_len += snprintf(newdmf + newdmf_len, (newdmf_size - newdmf_len),
"mib_name=\"%s\" ", devtab[i].mib); // [0 mib_name] mib

if (devtab[i].sysoid != NULL)
newdmf_len += snprintf(newdmf + newdmf_len, (newdmf_size - newdmf_len),
"oid=\"%s\" ", devtab[i].sysoid); // [5 sysOID] sysoid/NULL

newdmf_len += snprintf(newdmf + newdmf_len, (newdmf_size - newdmf_len),
"/>\n");
}
printf("</nut>\n");
fprintf(stderr, "\n=== DMF-Reindex: Indexed %d entries...\n\n", i);
newdmf_len += snprintf(newdmf + newdmf_len, (newdmf_size - newdmf_len),
"</nut>\n");
#ifdef DEBUG
fprintf(stderr,"[LAST: num=%zu (lenafter=%zu)] ", i, newdmf_len);
#endif
fprintf(stderr, "\n=== DMF-Reindex: Indexed %zu entries...\n\n", i);

mibdmf_parser_t * newdmp = mibdmf_parser_new();
if (!newdmp) {
fprintf(stderr,"=== DMF-Reindex: FATAL: Can not allocate the DMF verification parsing structures\n\n");
return ENOMEM;
}

fprintf(stderr, "=== DMF-Reindex: Loading DMF structures from prepared string (verification)\n\n");
result = mibdmf_parse_str(newdmf, newdmp);
// Error checking for one (just made) document makes sense and is definite
if ( result != 0 ) {
fprintf(stderr, "=== DMF-Reindex: The generated document FAILED syntax verification\n\n");
return result;
}

// Loop through reparsed device_table and compare to original one
fprintf(stderr, "=== DMF-Reindex: Verify reparsed content for snmp_device_table[]...\n\n");
snmp_device_id_t *newdevtab = mibdmf_get_device_table(newdmp);
if (!newdevtab)
{
fprintf(stderr,"=== DMF-Reindex: FATAL: Can not access the reparsed device_table\n");
return ENOMEM;
}

size_t j=-1, k=-1;
result=0;
// Make sure that all values we've considered are present in re-parse
for (k=0; devtab[k].oid != NULL || devtab[k].mib != NULL || devtab[k].sysoid != NULL ; k++)
{
int r = 0;
for (j=0; newdevtab[j].oid != NULL || newdevtab[j].mib != NULL || newdevtab[j].sysoid != NULL ; j++)
{ // Note: OID attribute may be empty or NULL, these are assumed equal
if ( (dmf_streq(newdevtab[j].oid, devtab[k].oid, false)
||dmf_streq(newdevtab[j].oid, "", false)
||dmf_streq(newdevtab[j].oid, NULL, false) )
&& dmf_streq(newdevtab[j].mib, devtab[k].mib, false)
&& dmf_streq(newdevtab[j].sysoid, devtab[k].sysoid, false) )
{
r = 1;
break;
}
}

if ( r==0 )
{
fprintf(stderr,"=== DMF-Reindex: mismatch in line %zu of the old table (no hits in new table)\n", k);
result++;
}
}

for (j=0; newdevtab[j].oid != NULL || newdevtab[j].mib != NULL || newdevtab[j].sysoid != NULL ; j++) ;

if ( i!=j )
{
fprintf(stderr,"=== DMF-Reindex: mismatch in amount of lines of old(%zu) and new(%zu) tables\n", i, j);
result++;
}

if ( result != 0 )
{
fprintf(stderr,"=== DMF-Reindex: The generated document FAILED content verification (%d issues)\n\n", result);
return result;
}

fprintf(stderr, "=== DMF-Reindex: Checks succeeded - printing generated DMF to stdout...\n\n");
printf("%s", newdmf);

// First we destroy the index tables that reference data in the list...
fprintf(stderr, "=== DMF-Reindex: Freeing data...\n\n");
dmf_parser_destroy();
alist_destroy(&list);
mibdmf_parser_destroy(&newdmp);
mibdmf_parser_destroy(&dmp);
free(newdmf);

fprintf(stderr, "=== DMF-Reindex: All done\n\n");

return 0;
// TODO: do we have and return fatal errors?
}
17 changes: 7 additions & 10 deletions scripts/DMF/dmf-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,36 +55,33 @@ main ()
lua_pcall(*lfunction, 0, 0, 0);
#endif

alist_t * list = alist_new(
NULL,(void (*)(void **))alist_destroy, NULL );
if (!list) {
fprintf(stderr,"FATAL: Can not allocate the auxiliary list\n");
mibdmf_parser_t * dmp = mibdmf_parser_new();
if (!dmp) {
fprintf(stderr,"FATAL: Can not allocate the DMF parsing structures\n");
return ENOMEM;
}
dmf_parser_init();

parse_dir("./", list);
mibdmf_parse_dir("./", dmp);

//Debugging
//mib2nut_info_t *m2n = get_mib2nut_table();
//print_mib2nut_memory_struct(m2n + 6);
//print_mib2nut_memory_struct(&pxgx_ups);
printf("=== DMF-Test: Loaded C structures (sample for 'powerware'):\n\n");
print_mib2nut_memory_struct((mib2nut_info_t *)
alist_get_element_by_name(list, "powerware")->values[0]);
alist_get_element_by_name(mibdmf_get_aux_list(dmp), "powerware")->values[0]);
printf("\n\n");
printf("=== DMF-Test: Original C structures (sample for 'powerware'):\n\n");
print_mib2nut_memory_struct(&powerware);
//End debugging

// First we destroy the index tables that reference data in the list...
printf("=== DMF-Test: Freeing data...\n\n");
dmf_parser_destroy();
alist_destroy(&list);
mibdmf_parser_destroy(&dmp);

#ifdef WITH_DMF_LUA
lua_close(*lfunction);
free(lfunction);
#endif
printf("=== DMF-Test: All done\n\n");
return 0;
}
Loading

0 comments on commit 53a9836

Please sign in to comment.