blob: 5f65b63c676331135a121e965310c3e7997a167b [file] [log] [blame]
#######################################################################
###generic include for XXX. Do not use directly.
###
### $Id$
########################################################################
@if $m2c_mark_boundary == 1@
/** START code generated by $RCSfile$ $Revision$ */
@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;
/*
* 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) {
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 $RCSfile$ $Revision$ */
@end@