592 lines
18 KiB
Plaintext
592 lines
18 KiB
Plaintext
#######################################################################
|
|
###generic include for XXX. Do not use directly.
|
|
###
|
|
########################################################################
|
|
@if $m2c_mark_boundary == 1@
|
|
/** START code generated by mfd-access-container-cached-defines.m2i */
|
|
@end@
|
|
##//####################################################################
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@if $m2c_processing_type eq 'h'@
|
|
|
|
@ if $m2c_data_cache != 1@
|
|
void ${context}_container_init(netsnmp_container **container_ptr_ptr);
|
|
@ else@
|
|
/*
|
|
* TODO:180:o: Review ${context} cache timeout.
|
|
* The number of seconds before the cache times out
|
|
*/
|
|
#define $context.uc_CACHE_TIMEOUT 60
|
|
|
|
void ${context}_container_init(netsnmp_container **container_ptr_ptr,
|
|
netsnmp_cache *cache);
|
|
@ end@ # data cache
|
|
void ${context}_container_shutdown(netsnmp_container *container_ptr);
|
|
|
|
int ${context}_container_load(netsnmp_container *container);
|
|
void ${context}_container_free(netsnmp_container *container);
|
|
|
|
@ if $m2c_data_cache == 1@
|
|
int ${context}_cache_load(netsnmp_container *container);
|
|
void ${context}_cache_free(netsnmp_container *container);
|
|
|
|
@ end@
|
|
@ if $m2c_include_examples == 1@
|
|
$example_start
|
|
/* *********************************************************************
|
|
* Since we have no idea how you really access your data, we'll go with
|
|
* a worst case example: a flat text file.
|
|
*/
|
|
#define MAX_LINE_SIZE 256
|
|
$example_end
|
|
@ end@ // example
|
|
@end@ // m2c_processing_type eq 'h'
|
|
##//####################################################################
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@if $m2c_processing_type eq 'c'@
|
|
/**
|
|
* container overview
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* container initialization
|
|
*
|
|
* @param container_ptr_ptr A pointer to a container pointer. If you
|
|
* create a custom container, use this parameter to return it
|
|
* to the MFD helper. If set to NULL, the MFD helper will
|
|
* allocate a container for you.
|
|
@ if $m2c_data_cache == 1@
|
|
* @param cache A pointer to a cache structure. You can set the timeout
|
|
* and other cache flags using this pointer.
|
|
@ end@
|
|
*
|
|
* This function is called at startup to allow you to customize certain
|
|
* aspects of the access method. For the most part, it is for advanced
|
|
* users. The default code should suffice for most cases. If no custom
|
|
* container is allocated, the MFD code will create one for your.
|
|
*
|
|
@ if $m2c_data_cache == 1@
|
|
* This is also the place to set up cache behavior. The default, to
|
|
* simply set the cache timeout, will work well with the default
|
|
* container. If you are using a custom container, you may want to
|
|
* look at the cache helper documentation to see if there are any
|
|
* flags you want to set.
|
|
*
|
|
@ end@
|
|
* @remark
|
|
* This would also be a good place to do any initialization needed
|
|
* for you data source. For example, opening a connection to another
|
|
* process that will supply the data, opening a database, etc.
|
|
*/
|
|
void
|
|
@ if $m2c_data_cache != 1@
|
|
${context}_container_init(netsnmp_container **container_ptr_ptr)
|
|
@ else@
|
|
${context}_container_init(netsnmp_container **container_ptr_ptr,
|
|
netsnmp_cache *cache)
|
|
@ end@
|
|
{
|
|
DEBUGMSGTL(("verbose:${context}:${context}_container_init","called\n"));
|
|
|
|
if (NULL == container_ptr_ptr) {
|
|
snmp_log(LOG_ERR,"bad container param to ${context}_container_init\n");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* For advanced users, you can use a custom container. If you
|
|
* do not create one, one will be created for you.
|
|
*/
|
|
*container_ptr_ptr = NULL;
|
|
|
|
@if $m2c_data_cache == 1@
|
|
if (NULL == cache) {
|
|
snmp_log(LOG_ERR,"bad cache param to ${context}_container_init\n");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* TODO:345:A: Set up $context cache properties.
|
|
*
|
|
* Also for advanced users, you can set parameters for the
|
|
* cache. Do not change the magic pointer, as it is used
|
|
* by the MFD helper. To completely disable caching, set
|
|
* cache->enabled to 0.
|
|
*/
|
|
cache->timeout = $context.uc_CACHE_TIMEOUT; /* seconds */
|
|
@end@
|
|
} /* ${context}_container_init */
|
|
|
|
/**
|
|
* container shutdown
|
|
*
|
|
* @param container_ptr A pointer to the container.
|
|
*
|
|
* This function is called at shutdown to allow you to customize certain
|
|
* aspects of the access method. For the most part, it is for advanced
|
|
* users. The default code should suffice for most cases.
|
|
*
|
|
* This function is called before ${context}_container_free().
|
|
*
|
|
* @remark
|
|
* This would also be a good place to do any cleanup needed
|
|
* for you data source. For example, closing a connection to another
|
|
* process that supplied the data, closing a database, etc.
|
|
*/
|
|
void
|
|
${context}_container_shutdown(netsnmp_container *container_ptr)
|
|
{
|
|
DEBUGMSGTL(("verbose:${context}:${context}_container_shutdown","called\n"));
|
|
|
|
if (NULL == container_ptr) {
|
|
snmp_log(LOG_ERR,"bad params to ${context}_container_shutdown\n");
|
|
return;
|
|
}
|
|
|
|
} /* ${context}_container_shutdown */
|
|
|
|
/**
|
|
* load initial data
|
|
*
|
|
* TODO:350:M: Implement $context data load
|
|
@ if $m2c_data_cache == 1@
|
|
* This function will also be called by the cache helper to load
|
|
* the container again (after the container free function has been
|
|
* called to free the previous contents).
|
|
@ end@
|
|
*
|
|
* @param container container to which items should be inserted
|
|
*
|
|
* @retval MFD_SUCCESS : success.
|
|
* @retval MFD_RESOURCE_UNAVAILABLE : Can't access data source
|
|
* @retval MFD_ERROR : other error.
|
|
*
|
|
* This function is called to load the index(es) (and data, optionally)
|
|
* for the every row in the data set.
|
|
*
|
|
* @remark
|
|
* While loading the data, the only important thing is the indexes.
|
|
* If access to your data is cheap/fast (e.g. you have a pointer to a
|
|
* structure in memory), it would make sense to update the data here.
|
|
* If, however, the accessing the data invovles more work (e.g. parsing
|
|
* some other existing data, or peforming calculations to derive the data),
|
|
* then you can limit yourself to setting the indexes and saving any
|
|
* information you will need later. Then use the saved information in
|
|
* ${context}_row_prep() for populating data.
|
|
*
|
|
* @note
|
|
* If you need consistency between rows (like you want statistics
|
|
* for each row to be from the same time frame), you should set all
|
|
* data here.
|
|
*
|
|
*/
|
|
int
|
|
${context}_container_load(netsnmp_container *container)
|
|
{
|
|
${context}_rowreq_ctx *rowreq_ctx;
|
|
size_t count = 0;
|
|
|
|
/*
|
|
* storage for each column
|
|
*/
|
|
@ foreach $node index@
|
|
@ include m2c_setup_node.m2i@
|
|
@ include node-storage.m2i@
|
|
@ end@ // foreach
|
|
|
|
/*
|
|
* temporary storage for index values
|
|
*/
|
|
@ foreach $node index@
|
|
@ include m2c_setup_node.m2i@
|
|
/*
|
|
* $m2c_node_summary
|
|
*/
|
|
@ if $m2c_node_needlength == 1@
|
|
@ eval $m2c_gi_maxlen = (126 - $node.oidlength - $m2c_gi_others)@
|
|
@ if $m2c_node_maxlen > $m2c_gi_maxlen@
|
|
@ eval $m2c_node_maxlen = $m2c_gi_maxlen@
|
|
/** 128 - 1(entry) - 1(col) - $m2c_gi_others(other indexes) = $m2c_node_maxlen */
|
|
@ end@
|
|
@ end@ # needlength
|
|
@ include node-storage.m2i@
|
|
@ end@ // foreach
|
|
|
|
@if $m2c_include_examples == 1@
|
|
|
|
/*
|
|
* this example code is based on a data source that is a
|
|
* text file to be read and parsed.
|
|
*/
|
|
FILE *filep;
|
|
char line[MAX_LINE_SIZE];
|
|
@end@ // examples
|
|
|
|
DEBUGMSGTL(("verbose:${context}:${context}_container_load","called\n"));
|
|
|
|
@if $m2c_include_examples == 1@
|
|
$example_start
|
|
/*
|
|
* open our data file.
|
|
*/
|
|
filep = fopen("/etc/dummy.conf", "r");
|
|
if(NULL == filep) {
|
|
return MFD_RESOURCE_UNAVAILABLE;
|
|
}
|
|
|
|
$example_end
|
|
@end@ // example
|
|
/*
|
|
* TODO:351:M: |-> Load/update data in the $context container.
|
|
* loop over your $context data, allocate a rowreq context,
|
|
* set the index(es) [and data, optionally] and insert into
|
|
* the container.
|
|
*/
|
|
while( 1 ) {
|
|
@ if $m2c_include_examples == 0@
|
|
/*
|
|
* check for end of data; bail out if there is no more data
|
|
*/
|
|
if( 1 )
|
|
break;
|
|
@ else@
|
|
$example_start
|
|
/*
|
|
* get a line (skip blank lines)
|
|
*/
|
|
do {
|
|
if (!fgets(line, sizeof(line), filep)) {
|
|
/* we're done */
|
|
fclose(filep);
|
|
filep = NULL;
|
|
}
|
|
} while (filep && (line[0] == '\n'));
|
|
|
|
/*
|
|
* check for end of data
|
|
*/
|
|
if(NULL == filep)
|
|
break;
|
|
|
|
/*
|
|
* parse line into variables
|
|
*/
|
|
$example_end
|
|
@ end@ # example
|
|
|
|
/*
|
|
* TODO:352:M: | |-> set indexes in new $context rowreq context.
|
|
@ eval $m2c_tmp = ""@
|
|
@ if ($m2c_data_allocate == 1) || ($m2c_data_init == 1)@
|
|
@ eval $m2c_tmp = "NULL"@
|
|
@ if ($m2c_data_allocate == 1) && ($m2c_data_init == 1)@
|
|
@ eval $m2c_tmp = "$m2c_tmp, NULL"@
|
|
* data context will be set from the first param (unless NULL,
|
|
* in which case a new data context will be allocated)
|
|
* the second param will be passed, with the row context, to
|
|
* ${context}rowreq_ctx_init.
|
|
@ else@
|
|
* data context will be set from the param (unless NULL,
|
|
* in which case a new data context will be allocated)
|
|
@ @end@
|
|
@ end@
|
|
*/
|
|
rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp);
|
|
if (NULL == rowreq_ctx) {
|
|
snmp_log(LOG_ERR, "memory allocation failed\n");
|
|
return MFD_RESOURCE_UNAVAILABLE;
|
|
}
|
|
if(MFD_SUCCESS != ${context}_indexes_set(rowreq_ctx
|
|
@ foreach $node index@
|
|
@ include m2c_setup_node.m2i@
|
|
@ if $m2c_node_needlength == 1@
|
|
, $node, ${node}_len
|
|
@ else@
|
|
, $node
|
|
@ end@
|
|
@ end@ # foreach index
|
|
)) {
|
|
snmp_log(LOG_ERR,"error setting index while loading "
|
|
"${context} data.\n");
|
|
${context}_release_rowreq_ctx(rowreq_ctx);
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* TODO:352:r: | |-> populate $context data context.
|
|
* Populate data context here. (optionally, delay until row prep)
|
|
*/
|
|
@if $m2c_data_transient == 0@ # persistent
|
|
/* non-TRANSIENT data: no need to copy. set pointer to data */
|
|
@else@
|
|
/*
|
|
* TRANSIENT or semi-TRANSIENT data:
|
|
* copy data or save any info needed to do it in row_prep.
|
|
*/
|
|
@ foreach $node nonindex@
|
|
@ include m2c_setup_node.m2i@
|
|
/*
|
|
* setup/save data for $node
|
|
* $m2c_node_summary
|
|
*/
|
|
@ if "$m2c_data_context" eq "generated"@
|
|
@ eval $m2c_ctx_lh = "$m2c_ctx_rh"@
|
|
@ eval $m2c_ctx_lhs = "$m2c_ctx_rhs"@
|
|
@ eval $m2c_ctx_rh = "$node"@
|
|
@ eval $m2c_ctx_rhs = "${node}_len"@
|
|
@ include generic-value-map.m2i@
|
|
|
|
@ end@ # data_context ! generated
|
|
@ end@ // for each
|
|
@end@ # transient
|
|
|
|
/*
|
|
* insert into table container
|
|
*/
|
|
CONTAINER_INSERT(container, rowreq_ctx);
|
|
++count;
|
|
}
|
|
@if $m2c_include_examples == 1@
|
|
|
|
$example_start
|
|
if(NULL != filep)
|
|
fclose(filep);
|
|
$example_end
|
|
@end@ # example
|
|
|
|
DEBUGMSGT(("verbose:${context}:${context}_container_load",
|
|
"inserted %d records\n", count));
|
|
|
|
return MFD_SUCCESS;
|
|
} /* ${context}_container_load */
|
|
|
|
/**
|
|
* container clean up
|
|
*
|
|
* @param container container with all current items
|
|
*
|
|
* This optional callback is called prior to all
|
|
* item's being removed from the container. If you
|
|
* need to do any processing before that, do it here.
|
|
*
|
|
* @note
|
|
* The MFD helper will take care of releasing all the row contexts.
|
|
@ if ($m2c_data_allocate == 1) && ($m2c_data_transient == 0)@
|
|
* If you did not pass a data context pointer when allocating
|
|
* the rowreq context, the one that was allocated will be deleted.
|
|
* If you did pass one in, it will not be deleted and that memory
|
|
* is your responsibility.
|
|
@ end@
|
|
*
|
|
*/
|
|
void
|
|
${context}_container_free(netsnmp_container *container)
|
|
{
|
|
DEBUGMSGTL(("verbose:${context}:${context}_container_free","called\n"));
|
|
|
|
/*
|
|
* TODO:380:M: Free $context container data.
|
|
*/
|
|
} /* ${context}_container_free */
|
|
|
|
@end@ // m2c_processing_type eq 'c'
|
|
########################################################################
|
|
##//####################################################################
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@if $m2c_processing_type eq 'i'@
|
|
@ if $m2c_data_cache == 1@
|
|
static void _container_free(netsnmp_container *container);
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
static int
|
|
_cache_load(netsnmp_cache *cache, void *vmagic)
|
|
{
|
|
DEBUGMSGTL(("internal:${context}:_cache_load","called\n"));
|
|
|
|
if((NULL == cache) || (NULL == cache->magic)) {
|
|
snmp_log(LOG_ERR, "invalid cache for ${context}_cache_load\n");
|
|
return -1;
|
|
}
|
|
|
|
/** should only be called for an invalid or expired cache */
|
|
netsnmp_assert((0 == cache->valid) || (1 == cache->expired));
|
|
|
|
/*
|
|
* call user code
|
|
*/
|
|
return ${context}_container_load((netsnmp_container*)cache->magic);
|
|
} /* _cache_load */
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
static void
|
|
_cache_free(netsnmp_cache *cache, void *magic)
|
|
{
|
|
netsnmp_container *container;
|
|
|
|
DEBUGMSGTL(("internal:${context}:_cache_free","called\n"));
|
|
|
|
if((NULL == cache) || (NULL == cache->magic)) {
|
|
snmp_log(LOG_ERR, "invalid cache in ${context}_cache_free\n");
|
|
return;
|
|
}
|
|
|
|
container = (netsnmp_container*)cache->magic;
|
|
|
|
_container_free(container);
|
|
} /* _cache_free */
|
|
|
|
@ end@ # cache
|
|
/**
|
|
* @internal
|
|
*/
|
|
static void
|
|
_container_item_free(${context}_rowreq_ctx *rowreq_ctx, void *context)
|
|
{
|
|
DEBUGMSGTL(("internal:${context}:_container_item_free","called\n"));
|
|
|
|
if(NULL == rowreq_ctx)
|
|
return;
|
|
|
|
${context}_release_rowreq_ctx(rowreq_ctx);
|
|
} /* _container_item_free */
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
static void
|
|
_container_free(netsnmp_container *container)
|
|
{
|
|
DEBUGMSGTL(("internal:${context}:_container_free","called\n"));
|
|
|
|
if (NULL == container) {
|
|
snmp_log(LOG_ERR, "invalid container in ${context}_container_free\n");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* call user code
|
|
*/
|
|
${context}_container_free(container);
|
|
|
|
/*
|
|
* free all items. inefficient, but easy.
|
|
*/
|
|
CONTAINER_CLEAR(container,
|
|
(netsnmp_container_obj_func *)_container_item_free,
|
|
NULL);
|
|
} /* _container_free */
|
|
|
|
/**
|
|
* @internal
|
|
* initialize the container with functions or wrappers
|
|
*/
|
|
void
|
|
_${context}_container_init(${context}_interface_ctx *if_ctx)
|
|
{
|
|
DEBUGMSGTL(("internal:${context}:_${context}_container_init","called\n"));
|
|
|
|
@ if $m2c_data_cache == 1@
|
|
/*
|
|
* cache init
|
|
*/
|
|
@ if 0@
|
|
if_ctx->cache =
|
|
netsnmp_cache_find_by_oid(PARTNER_oid, OID_LENGTH(PARTNER_oid));
|
|
@ else@
|
|
if_ctx->cache = netsnmp_cache_create(30, /* timeout in seconds */
|
|
_cache_load, _cache_free,
|
|
${context}_oid,
|
|
${context}_oid_size);
|
|
@ end@ // shared cache
|
|
|
|
if(NULL == if_ctx->cache) {
|
|
snmp_log(LOG_ERR, "error creating cache for ${context}\n");
|
|
return;
|
|
}
|
|
|
|
if_ctx->cache->flags = NETSNMP_CACHE_DONT_INVALIDATE_ON_SET;
|
|
|
|
${context}_container_init(&if_ctx->container, if_ctx->cache);
|
|
@ else@
|
|
/*
|
|
* container init
|
|
*/
|
|
${context}_container_init(&if_ctx->container);
|
|
@ end@ data cache
|
|
if(NULL == if_ctx->container) {
|
|
if_ctx->container = netsnmp_container_find("${context}:table_container");
|
|
if(NULL != if_ctx->container) {
|
|
/*
|
|
* When reporting container management errors, we log the container's
|
|
* name, so set it here.
|
|
*/
|
|
if_ctx->container->container_name = strdup("${context}");
|
|
}
|
|
}
|
|
if(NULL == if_ctx->container) {
|
|
snmp_log(LOG_ERR,"error creating container in "
|
|
"${context}_container_init\n");
|
|
return;
|
|
}
|
|
|
|
@ if $m2c_data_cache == 1@
|
|
if (NULL != if_ctx->cache)
|
|
if_ctx->cache->magic = (void*)if_ctx->container;
|
|
@ end@
|
|
} /* _${context}_container_init */
|
|
|
|
/**
|
|
* @internal
|
|
* shutdown the container with functions or wrappers
|
|
*/
|
|
void
|
|
_${context}_container_shutdown(${context}_interface_ctx *if_ctx)
|
|
{
|
|
DEBUGMSGTL(("internal:${context}:_${context}_container_shutdown","called\n"));
|
|
|
|
${context}_container_shutdown(if_ctx->container);
|
|
|
|
_container_free(if_ctx->container);
|
|
|
|
} /* _${context}_container_shutdown */
|
|
|
|
@end@ // m2c_processing_type eq 'i'
|
|
########################################################################
|
|
##//####################################################################
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@if $m2c_processing_type eq 'r'@
|
|
##
|
|
container summary
|
|
------------------------
|
|
The container data access code is for cases when you want to
|
|
store your data in the agent/sub-agent.
|
|
|
|
... to be continued...
|
|
|
|
|
|
@ if $m2c_data_cache == 1@
|
|
cache summary
|
|
------------------------
|
|
The container-cached data access code is for cases when you want to
|
|
cache your data in the agent/sub-agent.
|
|
|
|
... to be continued...
|
|
|
|
|
|
@ end@
|
|
@end@ // m2c_processing_type eq 'r'
|
|
########################################################################
|
|
##//####################################################################
|
|
@if $m2c_mark_boundary == 1@
|
|
/** END code generated by mfd-access-container-cached-defines.m2i */
|
|
@end@
|