summaryrefslogtreecommitdiff
path: root/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i
diff options
context:
space:
mode:
Diffstat (limited to 'local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i')
-rw-r--r--local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i1198
1 files changed, 1198 insertions, 0 deletions
diff --git a/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i b/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i
new file mode 100644
index 0000000..f4f3514
--- /dev/null
+++ b/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i
@@ -0,0 +1,1198 @@
+############################################################# -*- c -*-
+## generic include for XXX. Do not use directly.
+##
+## $Id$
+########################################################################
+##
+@eval $mfd_aue_wrap_param = "wrap_ctx"@
+@eval $mfd_aue_wrap_param_type = "${context}_interface_ctx *"@
+@eval $mfd_aue_wrap_param_decl = "$mfd_aue_wrap_param_type $mfd_aue_wrap_param"@
+##
+@eval $mfd_aue_param = "${context}_reg"@
+@eval $mfd_aue_param_type = "${context}_registration *"@
+@eval $mfd_aue_param_decl = "$mfd_aue_param_type $mfd_aue_param"@
+@eval $mfd_aue_param_cmt = "$mfd_aue_param Pointer to a $mfd_aue_param_type"
+##
+@if $m2c_mark_boundary == 1@
+/** START code generated by $RCSfile$ $Revision$ */
+@end@
+##//####################################################################
+##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@if $m2c_processing_type eq 'h'@
+##
+@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.
+ @ if $m2c_data_transient != 2@
+ @ print Example code is for fully transient data. Either turn off@
+ @ print m2c_include_examples or set m2c_data_transient to 2.@
+ @ exit@
+ @ end@
+ */
+#define MAX_LINE_SIZE 256
+$example_end
+
+@end@
+/**
+ * loop context
+ *
+ * ToDo:
+ * define loop context structure
+ *
+ * Since the actual loop is in the MFD handler, a loop contex parameter
+ * is provided to help you keep track of where you are in between calls
+ * to functions that you wrote and the master MFD handler calls. The
+ * structure of this context is user defineable, and is defined in the
+ * file ${table}_data_access.h.
+ *
+ * E.G., if your data is stored in a linked list, the obvious thing you
+ * want to know from one function call to the next is your current
+ * position in the linked list. Thus the easiest context to use is a
+ * pointer within the linked list. For an array, the current index to
+ * that array would be easiest.
+ *
+ * The funtion calls are actually passed a reference to the loop
+ * context, to allow the loop context to be allocated memory. Here are
+ * some simple examples definitions for various data formats. These
+ * definitions are used in examples later on.
+ *
+ */
+typedef struct ${context}_loop_context_s {
+ /*
+ * temporary context used during iteration
+ */
+ ${context}_rowreq_ctx *rowreq_ctx;
+@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@
+} ${context}_loop_context;
+
+/*
+ * define a reference to the loop context
+ *
+ * NOTE: DO NOT ADD ITEMS TO THIS STRUCTURE!
+ */
+typedef struct ${context}_ref_loop_ctx_s {
+ ${context}_loop_context *loop_ctx;
+} ${context}_ref_loop_ctx;
+
+int ${context}_loop_get_first( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
+ ${context}_ref_rowreq_ctx *rowreq_ctx_ref);
+int ${context}_loop_get_next( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
+ ${context}_ref_rowreq_ctx *rowreq_ctx_ref);
+int ${context}_loop_get_data( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
+ ${context}_ref_rowreq_ctx *rowreq_ctx_ref);
+int ${context}_loop_save_position($mfd_aue_param_decl,
+ ${context}_ref_loop_ctx *loop_ctx_ref,
+ ${context}_ref_loop_ctx *save_loop_ctx_ref, int reuse);
+int ${context}_loop_cleanup_context( $mfd_aue_param_decl, ${context}_ref_loop_ctx *ref);
+
+##
+@end@ // m2c_processing_type eq 'h'
+########################################################################
+##//####################################################################
+##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@if $m2c_processing_type eq 'i'@
+/**
+ * @internal
+ * wrapper around clean up a loop reference
+ */
+static int
+_${context}_loop_cleanup_context( $mfd_aue_wrap_param_decl,
+ ${context}_ref_loop_ctx *ref)
+{
+ DEBUGMSGTL(("internal:${context}:_${context}_loop_cleanup_context","called\n"));
+
+ return ${context}_loop_cleanup_context($mfd_aue_wrap_param->user_ctx, ref);
+} /* _${context}_loop_cleanup_context */
+
+/**
+ * @internal
+ * wrapper around save position
+ */
+static int
+_${context}_loop_save_position( $mfd_aue_wrap_param_decl, ${context}_ref_loop_ctx *ref,
+ ${context}_ref_loop_ctx *ref_copy, int reuse)
+{
+ DEBUGMSGTL(("internal:${context}:_${context}_loop_save_position","called\n"));
+
+ return ${context}_loop_save_position($mfd_aue_wrap_param->user_ctx, ref,
+ ref_copy, reuse);
+} /* _${context}_loop_save_position */
+
+/**
+ * @internal
+ * wrapper around user get_first to setup the index oid
+ */
+static int
+_${context}_loop_get_first_wrapper($mfd_aue_wrap_param_decl,
+ ${context}_ref_loop_ctx * loop_ctx_ref,
+ ${context}_ref_rowreq_ctx * rowreq_ctx_ref)
+{
+ int rc;
+ DEBUGMSGTL(("internal:${context}:_${context}_loop_get_first_wrapper","called\n"));
+
+ rc = ${context}_loop_get_first($mfd_aue_wrap_param->user_ctx, loop_ctx_ref,
+ rowreq_ctx_ref);
+ /*
+ * convert index to OID
+ */
+ if(SNMPERR_SUCCESS == rc ) {
+ netsnmp_assert((NULL != rowreq_ctx_ref) &&
+ (rowreq_ctx_ref->rowreq_ctx->oid_idx.oids == rowreq_ctx_ref->rowreq_ctx->oid_tmp));
+ rowreq_ctx_ref->rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp);
+ rc = ${context}_index_to_oid(&rowreq_ctx_ref->rowreq_ctx->oid_idx,
+ &rowreq_ctx_ref->rowreq_ctx->tbl_idx);
+ netsnmp_assert(rowreq_ctx_ref->rowreq_ctx->oid_idx.len !=
+ sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp));
+ }
+
+ return rc;
+} /* _${context}_loop_get_first_wrapper */
+
+/**
+ * @internal
+ * wrapper around user get_next to setup the index oid
+ */
+static int
+_${context}_loop_get_next_wrapper($mfd_aue_wrap_param_decl,
+ ${context}_ref_loop_ctx * loop_ctx_ref,
+ ${context}_ref_rowreq_ctx * rowreq_ctx_ref)
+{
+ int rc;
+ DEBUGMSGTL(("internal:${context}:_${context}_loop_get_next_wrapper","called\n"));
+
+ rc = ${context}_loop_get_next($mfd_aue_wrap_param->user_ctx, loop_ctx_ref,
+ rowreq_ctx_ref);
+ /*
+ * convert index to OID
+ */
+ if(SNMPERR_SUCCESS == rc ) {
+ netsnmp_assert((NULL != rowreq_ctx_ref) &&
+ (rowreq_ctx_ref->rowreq_ctx->oid_idx.oids == rowreq_ctx_ref->rowreq_ctx->oid_tmp));
+ rowreq_ctx_ref->rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp);
+ rc = ${context}_index_to_oid(&rowreq_ctx_ref->rowreq_ctx->oid_idx,
+ &rowreq_ctx_ref->rowreq_ctx->tbl_idx);
+ netsnmp_assert(rowreq_ctx_ref->rowreq_ctx->oid_idx.len !=
+ sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp));
+ }
+
+ return rc;
+} /* _${context}_loop_get_next_wrapper */
+
+@if $m2c_data_transient != 0@ #
+/**
+ * @internal
+ * get data wrapper to allocate context for the user
+ */
+static int
+_${context}_loop_get_data_wrapper($mfd_aue_wrap_param_decl,
+ ${context}_ref_loop_ctx * loop_ctx_ref,
+ ${context}_ref_rowreq_ctx * rowreq_ctx_ref)
+{
+// ${context}_rowreq_ctx *orig_ctx = rowreq_ctx_ref->rowreq_ctx;
+
+ DEBUGMSGTL(("internal:${context}:_${context}_loop_get_data_wrapper","called\n"));
+
+ return ${context}_loop_get_data($mfd_aue_wrap_param->user_ctx, loop_ctx_ref, rowreq_ctx_ref);
+} /* _${context}_loop_get_data_wrapper */
+
+@end@ // transient != 0
+/**
+ * @internal
+ * initialize the iterator container with functions or wrappers
+ */
+void
+_${context}_container_init(${context}_interface_ctx *if_ctx)
+{
+ DEBUGMSGTL(("internal:${context}:_${context}_container_init","called\n"));
+
+ if_ctx->container = netsnmp_container_iterator_get(/** registration */
+ if_ctx,
+ /** compare */
+ NULL,
+ /** get_first */
+ (Netsnmp_Iterator_Loop_Key*)_${context}_loop_get_first_wrapper,
+ /** get_next */
+ (Netsnmp_Iterator_Loop_Key*)_${context}_loop_get_next_wrapper,
+ /** get_data */
+@if $m2c_data_transient != 0@ #
+ (Netsnmp_Iterator_Loop_Data*)_${context}_loop_get_data_wrapper,
+@else@
+ NULL,
+@end@
+ /** save_pos */
+ (Netsnmp_Iterator_Ctx_Dup*)_${context}_loop_save_position,
+ /** init_context */
+ (Netsnmp_Iterator_Ctx*)NULL,
+ /** cleanup_context */
+ (Netsnmp_Iterator_Ctx*)_${context}_loop_cleanup_context,
+ /** free_user_ctx */
+ NULL,
+ /** sorted */
+ 0);
+} /* _${context}_container_init */
+
+##
+@end@ // m2c_processing_type eq 'i'
+########################################################################
+##//####################################################################
+##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@if $m2c_processing_type eq 'c'@
+/**
+ * unsorted-external overview
+ *
+ * The unsorted external data access code works by calling a few simple
+ * functions to get the index value for each row. Once the agent determines
+ * which row is needed to process an incoming request, another function
+ * is called to retrieve the data for that row.
+ *
+ * A simplified version of the pseudo-code looks like this:
+ *
+ * ${context}_loop_get_first(loop,data)
+ * while( no_error ) {
+ * if( best_match(data, key)
+ * ${context}_loop_save_position(loop,pos);
+ * ${context}_loop_get_next(loop,data)
+ * }
+ * ${context}_loop_get_data(pos,data)
+ * ${context}_loop_cleanup_context(loop)
+ */
+
+/***********************************************************************
+ *
+ * ITERATION
+ *
+ ***********************************************************************/
+
+/**
+ * get the first data index
+ *
+ * Summary
+ * -------
+ * This function is called to initialize the iterator loop context for a
+ * new iteration loop and return the index(es) for the first
+ * ${context}_data in the data set.
+ *
+ * Note that during the loop, 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 should limit yourself to setting the indexes. Extracting the
+ * can be put off until the desired row is found. See the notes on
+ * ${context}_loop_get_data().
+ *
+ * Note that this function does not correspond to a SNMP GET pdu, and
+ * you should return data items in whatever order they are already in.
+ * (In fact, if your data is already ordered in the same order as the
+ * SNMP indexes, you shouldn't be using the unsorted-access code).
+ *
+ * This function should update the table index (rowreq_ctx_ref->rowreq_ctx->tbl_idx)
+ * values for the raw data (rowreq_ctx_ref->rowreq_ctx->data).
+ *
+ * More Details
+ * ------------
+ * If there is currently no data available, return MFD_END_OF_DATA.
+ * Otherwise, you should set rowreq_ctx_ref->rowreq_ctx and its indexes.
+ *
+ * rowreq_ctx_ref->rowreq_ctx will be NULL. You should allocate a new context
+ * for this loop. [Alternatively, you could allocate one in
+ * ${context}_loop_init_context, save it in your
+ * ${context}_ref_loop_ctx, and use it here.]
+ *
+ * Once you have your context pointer, you should set the index (or indexes)
+ * in rowreq_ctx_ref->rowreq_ctx->tbl_idx to the appropriate value for this row. [If you
+ * use your loop_ctx_ref cleverly, you might be able to put this work in
+ * ${context}_loop_get_next, and simply call that function.]
+ *
+ * @param $mfd_aue_param_cmt
+ * @param loop_ctx_ref Pointer to your loop reference.
+ * @param rowreq_ctx_ref Pointer to a context reference.
+ *
+ * @retval MFD_SUCCESS : success.
+ * @retval MFD_END_OF_DATA : no data available
+ * @retval MFD_ERROR : error.
+ */
+int
+${context}_loop_get_first( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
+ ${context}_ref_rowreq_ctx *rowreq_ctx_ref)
+{
+ DEBUGMSGTL(("verbose:${context}:${context}_loop_get_first","called\n"));
+
+ netsnmp_assert(rowreq_ctx_ref);
+ netsnmp_assert(loop_ctx_ref);
+
+ /*
+ * allocate memory for new structure
+ */
+ loop_ctx_ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context);
+ if(NULL == loop_ctx_ref->loop_ctx)
+ return MFD_ERROR;
+
+ /*
+ * allocate a temporary context to use during iteration
+ */
+@ 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"@
+@ @end@
+@ end@
+ loop_ctx_ref->loop_ctx->rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp);
+ if(NULL == loop_ctx_ref->loop_ctx->rowreq_ctx) {
+ SNMP_FREE(loop_ctx_ref->loop_ctx);
+ return MFD_RESOURCE_UNAVAILABLE;
+ }
+
+ /*
+ * ToDo:
+ * set up loop context
+ */
+@if $m2c_include_examples == 1@
+$example_start
+ /*
+ * open our data file.
+ */
+ loop_ctx_ref->loop_ctx->filep = fopen("/etc/dummy.conf", "r");
+ if(NULL == loop_ctx_ref->loop_ctx->filep) {
+ return MFD_RESOURCE_UNAVAILABLE;
+ }
+
+$example_end
+@end@
+
+@ifconf ${table}_update_idx.m2i@
+@ include ${table}_update_idx.m2i@
+@else@
+@ if $m2c_include_examples == 1@
+$example_start
+ /*
+ * in this example, after opening the file, get next does the same thing
+ * as get first, we let's just call get next...
+ */
+ return ${context}_loop_get_next($mfd_aue_param, loop_ctx_ref, rowreq_ctx_ref);
+$example_end
+@ else@
+ /*
+ * we just need the index for now. Reuse the one in the loop context's
+ * temporary row request context. (rowreq_ctx_ref->rowreq_ctx->tbl_idx)
+ */
+ rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
+
+ /*
+ * ToDo:
+ * set local vars for index from loop_ctx_ref->loop_ctx
+ * this can be done in one of two ways:
+ */
+
+ /*
+ * 1) individually
+ */
+@ foreach $node index@
+@ include m2c_setup_node.m2i@
+ /*
+ * ToDo:
+ * set rowreq_ctx_ref->rowreq_ctx->tbl_idx->$node
+@ if $m2c_node_needlength == 1@
+ * and rowreq_ctx_ref->tbl_idx->${node}_len
+@ end@
+ */
+@ end@ #foreach
+
+ /*
+ * OR
+ */
+
+ /*
+ * 2) by calling ${context}_indexes_set()
+ * ${context}_indexes_set(rowreq_ctx_ref->tbl_idx,
+@ foreach $node index@
+@ include m2c_setup_node.m2i@
+@ if $m2c_node_needlength == 1@
+ * ${node}_ptr, ${node}_len
+@ else@
+ * $node
+@ end@
+@ end@ # foreach index
+ * );
+ */
+@ end@ # example
+@end@ #ifconf
+
+ return MFD_SUCCESS;
+} /* ${context}_loop_get_first */
+
+/**
+ * get the next data index
+ *
+ * Summary
+ * -------
+ * This function returns the next data item in the data set. The same
+ * caveat applies here as did above. The indexes are the important parts
+ * during loop processing.
+ *
+ * Note that this function does not correspond to a SNMP GET-NEXT pdu, and
+ * you should return data items in whatever order they are already in.
+ * (In fact, if your data is already ordered in the same order as the
+ * SNMP indexes, you shouldn't be using the unsorted-access code).
+ *
+ * More Details
+ * ------------
+ * rowreq_ctx_ref->rowreq_ctx will have been set in ${context}_loop_get_first.
+ *
+ * If there is currently no data available, return MFD_END_OF_DATA.
+ * Otherwise, you should set the indexes in rowreq_ctx_ref->rowreq_ctx->tbl_idx.
+ *
+ * You should set the index (or indexes) in rowreq_ctx_ref->rowreq_ctx->tbl_idx to the
+ * appropriate value for this row.
+ *
+ * @param $mfd_aue_param_cmt
+ * @param loop_ctx_ref Pointer to your loop reference.
+ * @param rowreq_ctx_ref Pointer to a context reference.
+ *
+ * @retval MFD_SUCCESS : success.
+ * @retval MFD_END_OF_DATA : no more data available
+ * @retval MFD_ERROR : error.
+ */
+int
+${context}_loop_get_next( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
+ ${context}_ref_rowreq_ctx *rowreq_ctx_ref)
+{
+ DEBUGMSGTL(("verbose:${context}:${context}_loop_get_next","called\n"));
+
+ netsnmp_assert(loop_ctx_ref && loop_ctx_ref->loop_ctx);
+ netsnmp_assert(rowreq_ctx_ref);
+
+ /*
+ * we just need the index for now. Reuse the one in the loop context's
+ * temporary row request context. (rowreq_ctx_ref->rowreq_ctx->tbl_idx)
+ */
+ rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
+
+@ if $m2c_include_examples == 1@
+$example_start
+ /*
+ * get a line (skip blank lines)
+ */
+ do {
+ if (!fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line),
+ loop_ctx_ref->loop_ctx->filep)) {
+ /* we're done */
+ fclose(loop_ctx_ref->loop_ctx->filep);
+ loop_ctx_ref->loop_ctx->filep = NULL;
+ }
+ } while (loop_ctx_ref->loop_ctx->filep && (loop_ctx_ref->loop_ctx->line[0] == '\n'));
+
+ /*
+ * check for end of data
+ */
+ if(NULL == loop_ctx_ref->loop_ctx->filep)
+ return MFD_END_OF_DATA;
+
+ /*
+ * ToDo:
+ * set local vars for index from loop_ctx_ref->loop_ctx
+ * this can be done in one of two ways:
+ */
+
+ /*
+ * 1) individually
+ */
+@ foreach $node index@
+@ include m2c_setup_node.m2i@
+ /*
+ * ToDo:
+ * set rowreq_ctx_ref->rowreq_ctx->tbl_idx->$node
+@ if $m2c_node_needlength == 1@
+ * and rowreq_ctx_ref->tbl_idx->${node}_len
+@ end@
+ */
+@ end@ #foreach
+
+ /*
+ * OR
+ */
+
+ /*
+ * 2) by calling ${context}_indexes_set()
+ * ${context}_indexes_set(rowreq_ctx_ref->tbl_idx,
+@ foreach $node index@
+@ include m2c_setup_node.m2i@
+@ if $m2c_node_needlength == 1@
+ * ${node}_ptr, ${node}_len
+@ else@
+ * $node
+@ end@
+@ end@ # foreach index
+ * );
+ */
+$example_end
+@ end@ # example
+
+ return MFD_SUCCESS;
+} /* ${context}_loop_get_next */
+
+/**
+ * duplicate the current loop reference
+ *
+ * Summary
+ * -------
+ * During loop iteration, the iterator keeps track of the row that
+ * is the current best match. This function is called when the
+ * current row is a better match than any previous row.
+ *
+ * You should save any information you need to be able to locate this row
+ * again from the current loop context to a new loop context.
+ *
+ * At the end of the loop, when the best match has been found, the saved
+ * loop context will be used to get the data for the row by calling
+ * ${context}_loop_get_data().
+@if $m2c_data_transient != 0@ # persistent
+ *
+ * Since your data is transient, you need to make a copy of it before
+ * the iterator moves on to the next row.
+@end@
+ *
+@if $m2c_data_transient != 0@ # persistent
+ * More Details
+ * ------------
+@ if $m2c_data_transient == 1@ # short term
+ * Since your data is semi-TRANSIENT data, you could just keep a pointer
+ * to the data in the loop reference. The data should then be copied in
+ * ${context}_loop_get_data().
+@ else@ # $m2c_data_transient == 2@ # copy immediately
+ * One idea would be to copy it space allocated in the loop reference
+ * structure. Another would be to simply have a pointer in the loop
+ * reference structure, and allocate memory here.
+ *
+@ end@
+@end@
+ * @param $mfd_aue_param_cmt
+ * @param loop_ctx_ref Reference to current loop context.
+ * @param save_loop_ctx_ref Reference to a loop context for saving the current
+ * position. If reuse is not set or
+ * save_loop_ctx_ref->loop_ctx is NULL, allocate
+ * a new one. If reuse is set, you may reuse the existing
+ * loop_ctx.
+ * @param reuse Indicates if an existing save_loop_ctx_ref->loop_ctx
+ * may be reused.
+ *
+ * @retval MFD_SUCCESS : success.
+ * @retval MFD_ERROR : error.
+ */
+int
+${context}_loop_save_position($mfd_aue_param_decl,
+ ${context}_ref_loop_ctx *loop_ctx_ref,
+ ${context}_ref_loop_ctx *save_loop_ctx_ref,
+ int reuse)
+{
+ DEBUGMSGTL(("verbose:${context}:${context}_loop_save_position","called\n"));
+
+ netsnmp_assert(loop_ctx_ref && save_loop_ctx_ref);
+
+ /*
+ * ToDo:
+ * 1) allocate new loop context, unless you can reuse a previous pointer.
+ * 2) save information for the position of loop_ctx_ref in save_loop_ctx_ref.
+ */
+ if((0 == reuse) || (NULL == save_loop_ctx_ref->loop_ctx))
+ save_loop_ctx_ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context);
+ if(NULL == save_loop_ctx_ref->loop_ctx) {
+ snmp_log(LOG_ERR, "could not allocate memory\n");
+ return MFD_ERROR;
+ }
+
+ /*
+ * if you can reuse a previously saved contex, just swap
+ * it out with the loop iterator
+ */
+ if(reuse && save_loop_ctx_ref->loop_ctx->rowreq_ctx) {
+ ${context}_rowreq_ctx * tmp_rowreq_ctx = save_loop_ctx_ref->loop_ctx->rowreq_ctx;
+ save_loop_ctx_ref->loop_ctx->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
+ loop_ctx_ref->loop_ctx->rowreq_ctx = tmp_rowreq_ctx;
+ }
+ else {
+ /*
+ * take the current pointer
+ */
+ save_loop_ctx_ref->loop_ctx->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
+
+ /*
+ * allocate a new context to replace the one you just took.
+ */
+@ 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"@
+@ @end@
+@ end@
+ loop_ctx_ref->loop_ctx->rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp);
+ if(NULL == loop_ctx_ref->loop_ctx->rowreq_ctx) {
+ SNMP_FREE(loop_ctx_ref->loop_ctx);
+ return MFD_ERROR;
+ }
+ }
+
+@if $m2c_data_transient == 0@ # persistent
+ /** non-TRANSIENT data: no need to copy */
+@elsif $m2c_data_transient == 1@ # short term
+ /** semi-TRANSIENT data: will copy data when index found */
+ /** only need to copy pertinent data from loop context */
+@elsif $m2c_data_transient == 2@ # copy immediately
+ /*
+ * TRANSIENT data: copy all the data.
+ */
+@end@
+@if $m2c_include_examples == 1@
+$example_start
+@ if $m2c_data_transient == 1@ # short term
+ /** save line to do that */
+ memcpy(save_loop_ctx_ref->loop_ctx->line, loop_ctx_ref->loop_ctx->line,
+ sizeof(loop_ctx_ref->loop_ctx->line));
+@ elsif $m2c_data_transient == 2@ # copy immediately
+@ foreach $node nonindex@
+@ include m2c_setup_node.m2i@
+ /*
+ * ToDo:
+ * set rowreq_ctx_ref->${m2c_data_item}$node
+ * from the loop context
+ */
+@ end@
+@ end@
+$example_end
+@end@ # example
+
+ return MFD_SUCCESS;
+} /* ${context}_loop_save_position */
+
+@if $m2c_data_transient != 0@ # semi-transient
+/**
+ * set ${context}_data from a data context
+ *
+ * Summary
+ * -------
+ * At the end of the loop, when the best match has been found, the saved
+ * loop context will be used to get the data for the row by calling
+ * ${context}_loop_get_data().
+ *
+ * You should return a fully populated row request context in
+ * rowreq_ctx_ref->rowreq_ctx.
+ *
+ * More Details
+ * ------------
+ * @param $mfd_aue_param_cmt
+ * @param loop_ctx_ref pointer to your loop reference.
+ * @param rowreq_ctx_ref pointer to a context reference.
+ */
+int
+${context}_loop_get_data( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
+ ${context}_ref_rowreq_ctx *rowreq_ctx_ref)
+{
+ DEBUGMSGTL(("verbose:${context}:${context}_loop_get_data","called\n"));
+
+ netsnmp_assert((NULL != loop_ctx_ref) && (NULL != loop_ctx_ref->loop_ctx));
+ netsnmp_assert(NULL != rowreq_ctx_ref);
+ netsnmp_assert(NULL != rowreq_ctx_ref->rowreq_ctx);
+
+ /*
+ * take temporary row request context from loop context
+ */
+ rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
+ loop_ctx_ref->loop_ctx->rowreq_ctx = NULL;
+
+ /*
+ * copy data to the data context (rowreq_ctx_ref->${m2c_data_item})
+@ if $m2c_include_examples == 1@
+ * in loop_save_position, we saved line to do that
+@ end@
+ */
+@ foreach $node nonindex@
+@ include m2c_setup_node.m2i@
+ /*
+ * $m2c_node_summary
+ */
+@ eval $m2c_ctx_lh = "rowreq_ctx_ref->$m2c_ctx_rh"@
+@ eval $m2c_ctx_lhs = "rowreq_ctx_ref->$m2c_ctx_rhs"@
+@ eval $m2c_ctx_rh = "loop_ctx_ref->loop_ctx->$node"@
+@ eval $m2c_ctx_rhs = "loop_ctx_ref->loop_ctx->${node}_len"@
+@ include generic-value-map.m2i@
+
+@ end@
+
+ return MFD_SUCCESS;
+} /* ${context}_loop_get_data */
+
+@end@ // if $m2c_data_transient != 0
+
+/**
+ * clean up a loop reference
+ *
+ * Summary
+ * -------
+ * This function will be called once the loop iteration has completed
+ * to release any memory or resources allocated for the loop context.
+ *
+ * More Details
+ * ------------
+ * @param $mfd_aue_param_cmt
+ * @param loop_ctx_ref Pointer to your loop reference.
+ *
+ * @retval MFD_SUCCESS : success.
+ * @retval MFD_ERROR : error.
+ */
+int
+${context}_loop_cleanup_context( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref)
+{
+ DEBUGMSGTL(("verbose:${context}:${context}_loop_cleanup_context","called\n"));
+
+ netsnmp_assert(loop_ctx_ref);
+
+ if(!loop_ctx_ref->loop_ctx)
+ return MFD_ERROR;
+
+ /*
+ * release the row request context, if it wasn't taken
+ */
+ if(loop_ctx_ref->loop_ctx->rowreq_ctx)
+ ${context}_release_rowreq_ctx(loop_ctx_ref->loop_ctx->rowreq_ctx);
+
+ /*
+ * ToDo:
+ * release resources
+ */
+@if $m2c_include_examples == 1@
+$example_start
+ /*
+ * close file
+ */
+ if(loop_ctx_ref->loop_ctx->filep)
+ fclose(loop_ctx_ref->loop_ctx->filep);
+$example_end
+
+@end@
+ /*
+ * free loop context
+ */
+ free(loop_ctx_ref->loop_ctx);
+
+ return MFD_SUCCESS;
+} /* ${context}_loop_cleanup_context */
+
+@end@ // m2c_processing_type eq 'c'
+########################################################################
+##//####################################################################
+##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@if $m2c_processing_type eq 'r'@
+##
+ unsorted-external summary
+ -------------------------
+ The unsorted-external data access code is for cases when you data is
+ kept UNSORTED and EXTERNAL to the agent/sub-agent.
+
+ This code was generated based on the following assumptions or settings:
+
+ 1) The raw data for this table is UNSORTED.
+ @if $mfd_readme_verbose != 0@
+
+ UNSORTED data is data that is not kept in the same order as the way
+ SNMP expects the index(es) for the table to be kept. [It could very
+ well be sorted in some other order, but for the purpose of SNMP, the
+ order is incorrect.] If you're not sure if your data is sorted
+ in an SNMP compliant way, its likely not.
+
+ Because the raw data is unsorted, to satisfy a particular request, the
+ entire data set must be examined to find the apropriate index. This
+ is done via a simple loop. The MFD handler will call your get_first
+ function and the call the get_next function repeatedly, until it
+ returns SNMPERR_NO_VARS.
+ @end@
+
+ 2) The raw data for this table is EXTERNAL.
+ @if $mfd_readme_verbose != 0@
+
+ EXTERNAL data is data that is owned by some other process,
+ device, file or mechanism. The agent must use some interface to
+ read or modify the data. An external process may modify the data
+ without the agent's knowledge. For example, the Net-SNMP agent
+ implements the interface table (ifTable), which reports on
+ network interfaces. The host operating system owns this data, and
+ Net-SNMP must use system calls to report or manipulate the data.
+ Examples of external data include data stored in kernel space, in
+ files, in another non-memory shared process, and data stored in
+ devices.
+ @end@
+
+ 3) The raw data for this table is TRANSIENT.
+ @if $mfd_readme_verbose != 0@
+
+ TRANSIENT data is data that may be overwritten by another funtion
+ or process. For example, many OS functions return data in a
+ static buffer that will be reused the next time the function is
+ called. Because of this, we will assume that you will copy the
+ raw data retrieved from these other sources to a generated
+ structure for use within the Net-SNMP agent. (Don't worry, we'll
+ help you)
+ @end@
+
+
+##
+## this should be syncronized with master version of comments in
+## mfd-access-unsorted-external-body.m2i You should be able to copy
+## the comments here and replace " * " with " ".
+##
+ The unsorted external data access code works by calling a few simple
+ functions to get the index value for each row. Once the agent determines
+ which row is needed to process an incoming request, another function
+ is called to retrieve the data for that row.
+
+ A simplified version of the pseudo-code looks like this:
+
+ ${context}_loop_init_context(loop)
+ ${context}_loop_get_first(loop,data)
+ while( no_error ) {
+ if( best_match(data, key)
+ ${context}_loop_save_position(loop,pos);
+ ${context}_loop_get_next(loop,data)
+ }
+ ${context}_loop_get_data(pos,data)
+ ${context}_loop_cleanup_context(loop)
+##
+## end sync
+##
+
+ We will talk about each individual step below.
+
+
+########################################################################
+ Defining context for the loop
+ -----------------------------
+ ToDo : typedef ${context}_loop_context
+ WHERE: ${table}_data_access.h
+
+ @if $mfd_readme_verbose != 0@
+##
+## this should be syncronized with master version of comments in
+## mfd-access-unsorted-external-body.m2i You should be able to copy
+## the comments here and replace " * " with " ".
+##
+ Since the actual loop is in the MFD handler, a loop contex parameter
+ is provided to help you keep track of where you are in between calls
+ to functions that you wrote and the master MFD handler calls. The
+ structure of this context is user defineable, and is defined in the
+ file ${table}_data_access.h.
+
+ E.G., if your data is stored in a linked list, the obvious thing you
+ want to know from one function call to the next is your current
+ position in the linked list. Thus the easiest context to use is a
+ pointer within the linked list. For an array, the current index to
+ that array would be easiest.
+
+ The funtion calls are actually passed a reference to the loop
+ context, to allow the loop context to be allocated memory. Here are
+ some simple examples definitions for various data formats. These
+ definitions are used in examples later on.
+##
+## end sync
+##
+
+ Linked list
+ -----------
+ typedef list_node ${context}_loop_context;
+
+ Array
+ -----
+ typedef integer ${context}_loop_context;
+
+ File
+ ----
+ typedef struct ${context}_loop_context_s {
+ char * file_name;
+ FILE * f;
+ char line[128];
+ } ${context}_loop_context;
+
+ @end@
+
+########################################################################
+ Initialization
+ --------------
+ ToDo : Initialization
+ FUNC : ${context}_loop_init_data
+ WHERE: ${table}_data_access.c
+
+ @if $mfd_readme_verbose != 0@
+ The ${context}_loop_init_data function will be called during startup to
+ allow for any initialization needed for the data access routines.
+
+ @end@
+
+########################################################################
+ Preparing for the loop
+ ----------------------
+ ToDo : initialize loop context
+ FUNC : ${context}_loop_init_context
+ WHERE: ${table}_data_access.c
+
+ @if $mfd_readme_verbose != 0@
+##
+## this should be syncronized with master version of comments in
+## mfd-access-unsorted-external-body.m2i You should be able to copy
+## the comments here and replace " * " with " ".
+##
+ This function will be called before the start of a new itertion over
+ the data. The loop context that is initialized here will be passed to
+ ${context}_loop_get_first and ${context}_loop_get_next.
+
+ Set the loop context variable ref->loop_ctx so that the iteration
+ functions (get_first and get_next) can locate the apropriate data
+ context.
+##
+## end sync
+##
+
+ The primary purpose of the loop_init_context call is to initialize
+ the loop context data (ref). Here are some simple examples, based on the
+ earlier example loop contexts.
+
+ Linked list
+ -----------
+ ref->loop_ctx = my_table_head_ptr;
+
+ Array
+ -----
+ /* instead of actually allocating memory, just use the pointer */
+ /* as an integer */
+ (integer)(ref->loop_ctx) = 0;
+
+ File
+ ----
+ ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context);
+ /* error checking here */
+ ref->loop_ctx->file_name = (char*) reg->mfd_user_ctx;
+ ref->loop_ctx->f = fopen( ref->loop_ctx->file_name, "r+" );
+
+ @end@
+
+########################################################################
+ The Loop
+ --------
+ ToDo : return raw data
+ FUNC : ${context}_loop_get_first
+ WHERE: ${table}_data_access.c
+
+ @if $mfd_readme_verbose != 0@
+##
+## this should be syncronized with master version of comments in
+## mfd-access-unsorted-external-body.m2i You should be able to copy
+## the comments here and replace " * " with " ".
+##
+ This function is called to return set the index(es) for the first
+ ${context}_data in the data set.
+
+ Note that during the loop, 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 should limit yourslef to setting the indexes. Extracting the
+ can be put off until the desired row is found See the notes on
+ ${context}_loop_get_data().
+
+ Note that this function does not correspond to a SNMP GET pdu, and
+ you should return data items in whatever order they are already in.
+ (In fact, if your data is already ordered in the same order as the
+ SNMP indexes, you shouldn't be using the unsorted-access code).
+
+ This function should update the table index (rowreq_ctx_ref->rowreq_ctx->tbl_idx)
+ values for the raw data (rowreq_ctx_ref->rowreq_ctx->data).
+##
+## end sync
+##
+
+ Linked list
+ -----------
+ rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx;
+
+ Array
+ -----
+ /* assuming registration has array of pointers */
+ rowreq_ctx_ref->rowreq_ctx->data = reg->mfd_user_ctx[(integer)(ref->loop_ctx)];
+
+ File
+ ----
+ fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line),
+ loop_ctx_ref->loop_ctx->f);
+ rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx->line;
+
+ @end@
+
+ ToDo : return raw data
+ FUNC : ${context}_loop_get_next
+ WHERE: ${table}_data_access.c
+
+ @if $mfd_readme_verbose != 0@
+##
+## this should be syncronized with master version of comments in
+## mfd-access-unsorted-external-body.m2i You should be able to copy
+## the comments here and replace " * " with " ".
+##
+ This function returns the next data item in the data set. The same
+ caveat applies here as did above. The indexes are the important parts
+ during loop processing.
+
+ Note that this function does not correspond to a SNMP GET-NEXT pdu, and
+ you should return data items in whatever order they are already in.
+ (In fact, if your data is already ordered in the same order as the
+ SNMP indexes, you shouldn't be using the unsorted-access code).
+##
+## end sync
+##
+
+ Linked list
+ -----------
+ loop_ctx_ref->loop_ctx = loop_ctx_ref->loop_ctx->next;
+ rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx;
+
+ Array
+ -----
+ ++((integer)(ref->loop_ctx));
+ /* assuming registration has array of pointers */
+ rowreq_ctx_ref->rowreq_ctx->data = reg->mfd_user_ctx[(integer)(ref->loop_ctx)];
+
+ File
+ ----
+ fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line),
+ loop_ctx_ref->loop_ctx->f);
+ rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx->line;
+
+ @end@
+
+########################################################################
+ Updating the Index
+ ------------------
+ ToDo : update index for the raw data
+ FUNC : ${context}_indexes_set
+ WHERE: ${table}_data_access.c
+
+ This is a convenience function for setting the index context from
+ the native C data. Where necessary, value mapping should be done.
+
+ @if $mfd_readme_verbose == 1@
+ This function should update the table index values (found in
+ tbl_idx) for the given raw data.
+
+ @end@
+
+########################################################################
+ Saving a position in the loop
+ -----------------------------
+ ToDo : Saving a position in the loop
+ FUNC : ${context}_loop_save_position
+ WHERE: ${table}_data_access.c
+
+ @if $mfd_readme_verbose != 0@
+##
+## this should be syncronized with master version of comments in
+## mfd-access-unsorted-external-body.m2i You should be able to copy
+## the comments here and replace " * " with " ".
+##
+ During loop iteration, the iterator keeps track of the row that
+ is the current best match. This function is called when the
+ current row is a better match than any previous row.
+
+ You should save any information you need to be able to locate this row
+ again from the current loop context to a new loop context.
+
+ At the end of the loop, when the best match has been found, the saved
+ loop context will be used to get the data for the row by calling
+ ${context}_loop_get_data().
+@if $m2c_data_transient != 0@ # persistent
+
+ Since your data is transient, you need to make a copy of it before
+ the iterator moves on to the next row.
+@end@
+##
+## end sync
+##
+
+ @end@
+
+########################################################################
+ Returning Data For an Index
+ ---------------------------
+ ToDo : copy transient raw data to generated structure
+ FUNC : ${context}_loop_get_data
+ WHERE: ${table}_data_access.c
+
+ @if $mfd_readme_verbose != 0@
+##
+## this should be syncronized with master version of comments in
+## mfd-access-unsorted-external-body.m2i You should be able to copy
+## the comments here and replace " * " with " ".
+##
+ At the end of the loop, when the best match has been found, the saved
+ loop context will be used to get the data for the row by calling
+ ${context}_loop_get_data().
+##
+## end sync
+##
+
+ @end@
+
+########################################################################
+ Cleaning up after the loop
+ --------------------------
+ ToDo : release any allocated memory
+ FUNC : ${context}_loop_cleanup_context
+ WHERE: ${table}_data_access.c
+
+ @if $mfd_readme_verbose != 0@
+##
+## this should be syncronized with master version of comments in
+## mfd-access-unsorted-external-body.m2i You should be able to copy
+## the comments here and replace " * " with " ".
+##
+ This function will be called once the loop iteration has completed
+ to release any memory allocated for loop reference.
+##
+## end sync
+##
+ The purpose of the loop_cleanup_context call is to release any memory
+ allocated for the loop context data. Here are some simple examples, based
+ on the earlier example loop contexts.
+
+ Linked list
+ -----------
+ /* nothing to do */
+
+ Array
+ -----
+ /* nothing to do */
+
+ File
+ ----
+ free(ref->loop_ctx);
+
+ @end@
+
+##
+@end@ // m2c_processing_type eq 'r
+########################################################################
+@if $m2c_mark_boundary == 1@
+/** END code generated by $RCSfile$ $Revision$ */
+@end@