blob: 31559ac838030b2f987185c332821aa729835e92 [file] [log] [blame]
## -*- c -*-
##
## For documentation on the code generated by this configuration file,
## see the file agent/helpers/table_array.c.
##
######################################################################
## Do the .h file
## @perleval $vars{shortname} =~ s/([A-Z])[a-z]+/$1/g@
######################################################################
@foreach $i table@
@open ${i}.h@
@eval $hack = "Id"
/*
* Note: this file originally auto-generated by mib2c using
* $Id$
*
* $$hack:$
*
* Yes, there is lots of code here that you might not use. But it is much
* easier to remove code than to add it!
*/
#ifndef $i.uc_H
#define $i.uc_H
#ifdef __cplusplus
extern "C" {
#endif
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/library/container.h>
#include <net-snmp/agent/table_array.h>
@eval $ext_index = 0@
@foreach $idx index@
@if "$idx" ne ""@
@eval $found = "external"@
@foreach $c column@
@if "$idx" eq "$c"@
@eval $found = "internal"@
@end@
@end@
/** Index $idx is $found */
@if "$found" eq "external"@
@eval $ext_index = 1@
@end@
@end@
@end@
typedef struct ${i}_context_s {
netsnmp_index index; /** THIS MUST BE FIRST!!! */
/*************************************************************
* You can store data internally in this structure.
*
* TODO: You will probably have to fix a few types here...
*/
@if $ext_index != 0@
/** TODO: add storage for external index(s)! */
@end@
@foreach $c column@
/** $c.syntax = $c.type */
@eval $have_type = 0@
@if "$c.type" eq "ASN_OCTET_STR"@
@eval $have_type = 1@
@eval $o_len = "65535"@
@if "$c.syntax" eq "DisplayString"@
@eval $o_len = "255"@
@end@
@if "$c.syntax" eq "SnmpAdminString"@
@eval $o_len = "255"@
@end@
unsigned char $c[$o_len];
long ${c}_len;
@end@
@if "$c.type" eq "ASN_OBJECT_ID"@
@eval $have_type = 1@
oid $c[MAX_OID_LEN];
long ${c}_len;
@end@
@if "$c.type" eq "ASN_UNSIGNED"@
@eval $have_type = 1@
unsigned long $c;
@end@
@if "$c.type" eq "ASN_TIMETICKS"@
@eval $have_type = 1@
unsigned long $c;
@end@
@if "$c.type" eq "ASN_IPADDRESS"@
@eval $have_type = 1@
unsigned long $c;
@end@
@if "$c.type" eq "ASN_UINTEGER"@
@eval $have_type = 1@
unsigned long $c;
@end@
@if "$c.type" eq "ASN_INTEGER"@
@eval $have_type = 1@
long $c;
@end@
@if "$c.type" eq "ASN_COUNTER"@
@eval $have_type = 1@
unsigned long $c;
@end@
@if $have_type == 0@
/** TODO: Is this type correct? */
long $c;
@end@
@end@
/*
* OR
*
* Keep a pointer to your data
*/
void * data;
/*
*add anything else you want here
*/
} ${i}_context;
/*************************************************************
* function declarations
*/
void init_$i(void);
void initialize_table_$i(void);
const ${i}_context * ${i}_get_by_idx(netsnmp_index *);
const ${i}_context * ${i}_get_by_idx_rs(netsnmp_index *,
int row_status);
int ${i}_get_value(netsnmp_request_info *, netsnmp_index *, netsnmp_table_request_info *);
/*************************************************************
* oid declarations
*/
extern const oid ${i}_oid[];
extern const size_t ${i}_oid_len;
#define ${i}_TABLE_OID $i.commaoid
/*************************************************************
* column number definitions for table $i
*/
@eval $minv = 0xffffffff@
@eval $maxv = 0@
@foreach $c column@
#define COLUMN_$c.uc $c.subid
@if ! $c.noaccess@
@eval $minv = min($minv, $c.subid)@
@eval $maxv = max($maxv, $c.subid)@
@end@
@if "$c.syntax" eq "RowStatus"@
@eval $rs_name = "$c"@
@end@
@if "$c.syntax" eq "StorageType"@
@eval $st_name = "$c"@
@end@
@end@
#define ${i}_COL_MIN $minv
#define ${i}_COL_MAX $maxv
/* comment out the following line if you don't want a custom sort */
#define ${i}_CUSTOM_SORT
@if "$rs_name" ne ""@
/* uncommend the following line if you allow modifications to an
* active row */
/** define ${i}_CAN_MODIFY_ACTIVE_ROW */
@end@
@if $i.settable@
int ${i}_extract_index( ${i}_context * ctx, netsnmp_index * hdr );
void ${i}_set_reserve1( netsnmp_request_group * );
void ${i}_set_reserve2( netsnmp_request_group * );
void ${i}_set_action( netsnmp_request_group * );
void ${i}_set_commit( netsnmp_request_group * );
void ${i}_set_free( netsnmp_request_group * );
void ${i}_set_undo( netsnmp_request_group * );
${i}_context * ${i}_duplicate_row( ${i}_context* );
netsnmp_index * ${i}_delete_row( ${i}_context* );
@if "$rs_name" ne ""@
int ${i}_can_activate(${i}_context *undo_ctx,
${i}_context *row_ctx,
netsnmp_request_group * rg);
int ${i}_can_deactivate(${i}_context *undo_ctx,
${i}_context *row_ctx,
netsnmp_request_group * rg);
@end@
int ${i}_can_delete(${i}_context *undo_ctx,
${i}_context *row_ctx,
netsnmp_request_group * rg);
@if $i.creatable@
${i}_context * ${i}_create_row( netsnmp_index* );
@end@
@end@
#ifdef ${i}_CUSTOM_SORT
${i}_context * ${i}_get( const char *name, int len );
#endif
#ifdef __cplusplus
}
#endif
#endif /** $i.uc_H */
@end@
######################################################################
## Do the .c file
######################################################################
@foreach $i table@
@open ${i}.c@
@eval $hack = "Id"@
/*
* Note: this file originally auto-generated by mib2c using
* $Id$
*
* $$hack:$
*
*
* For help understanding NET-SNMP in general, please check the
* documentation and FAQ at:
*
* http://www.net-snmp.org/
*
*
* For help understanding this code, the agent and how it processes
* requests, please check the following references.
*
* http://www.net-snmp.org/tutorial-5/
*
*
* You can also join the #net-snmp channel on irc.freenode.net
* and ask for help there.
*
*
* And if all else fails, send a detailed message to the developers
* describing the problem you are having to:
*
* net-snmp-coders@lists.sourceforge.net
*
*
* Yes, there is lots of code here that you might not use. But it is much
* easier to remove code than to add it!
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/library/snmp_assert.h>
#include "${i}.h"
static netsnmp_handler_registration *my_handler = NULL;
static netsnmp_table_array_callbacks cb;
const oid ${i}_oid[] = { ${i}_TABLE_OID };
const size_t ${i}_oid_len = OID_LENGTH(${i}_oid);
#ifdef ${i}_CUSTOM_SORT
/************************************************************
* keep binary tree to find context by name
*/
static int ${i}_cmp( const void *lhs, const void *rhs );
/************************************************************
* compare two context pointers here. Return -1 if lhs < rhs,
* 0 if lhs == rhs, and 1 if lhs > rhs.
*/
static int
${i}_cmp( const void *lhs, const void *rhs )
{
${i}_context *context_l =
(${i}_context *)lhs;
${i}_context *context_r =
(${i}_context *)rhs;
/*
* check primary key, then secondary. Add your own code if
* there are more than 2 keys
*/
int rc;
/*
* TODO: implement compare. Remove this ifdef code and
* add your own code here.
*/
#ifdef TABLE_CONTAINER_TODO
snmp_log(LOG_ERR,
"${i}_compare not implemented! Container order undefined\n" );
return 0;
#endif
/*
* EXAMPLE (assuming you want to sort on a name):
*
* rc = strcmp( context_l->xxName, context_r->xxName );
*
* if(rc)
* return rc;
*
* TODO: fix secondary keys (or delete if there are none)
*
* if(context_l->yy < context_r->yy)
* return -1;
*
* return (context_l->yy == context_r->yy) ? 0 : 1;
*/
}
/************************************************************
* search tree
*/
/** TODO: set additional indexes as parameters */
${i}_context *
${i}_get( const char *name, int len )
{
${i}_context tmp;
/** we should have a custom container */
netsnmp_assert(cb.container->next != NULL);
/*
* TODO: implement compare. Remove this ifdef code and
* add your own code here.
*/
#ifdef TABLE_CONTAINER_TODO
snmp_log(LOG_ERR, "${i}_get not implemented!\n" );
return NULL;
#endif
/*
* EXAMPLE:
*
* if(len > sizeof(tmp.xxName))
* return NULL;
*
* strncpy( tmp.xxName, name, sizeof(tmp.xxName) );
* tmp.xxName_len = len;
*
* return CONTAINER_FIND(cb.container->next, &tmp);
*/
}
#endif
/************************************************************
* Initializes the $i module
*/
void
init_$i(void)
{
initialize_table_$i();
/*
* TODO: perform any startup stuff here, such as
* populating the table with initial data.
*
* ${i}_context * new_row = create_row(index);
* CONTAINER_INSERT(cb.container,new_row);
*/
}
@if $i.settable@
/************************************************************
* the *_row_copy routine
*/
static int ${i}_row_copy(${i}_context * dst,
${i}_context * src)
{
if(!dst||!src)
return 1;
/*
* copy index, if provided
*/
if(dst->index.oids)
free(dst->index.oids);
if(snmp_clone_mem( (void*)&dst->index.oids, src->index.oids,
src->index.len * sizeof(oid) )) {
dst->index.oids = NULL;
return 1;
}
dst->index.len = src->index.len;
/*
* copy components into the context structure
*/
@if $ext_index != 0@
/** TODO: add code for external index(s)! */
@end@
@foreach $c column@
@eval $have_type = 0@
@if "$c.type" eq "ASN_OCTET_STR"@
@eval $have_type = 1@
memcpy( dst->$c, src->$c, src->${c}_len );
dst->${c}_len = src->${c}_len;
@end@
@if "$c.type" eq "ASN_OBJECT_ID"@
@eval $have_type = 1@
memcpy( dst->$c, src->$c, src->${c}_len );
dst->${c}_len = src->${c}_len;
@end@
@if $have_type == 0@
dst->$c = src->$c;
@end@
@end@
return 0;
}
/**
* the *_extract_index routine
*
* This routine is called when a set request is received for an index
* that was not found in the table container. Here, we parse the oid
* in the the individual index components and copy those indexes to the
* context. Then we make sure the indexes for the new row are valid.
*/
int
${i}_extract_index( ${i}_context * ctx, netsnmp_index * hdr )
{
/*
* temporary local storage for extracting oid index
*
* extract index uses varbinds (netsnmp_variable_list) to parse
* the index OID into the individual components for each index part.
*/
@if $ext_index != 0@
/** TODO: add storage for external index(s)! */
@end@
@eval $first_idx = ""@
@foreach $idx index@
@if "$first_idx" eq ""@
@eval $first_idx = $idx@
@end@
netsnmp_variable_list var_$idx;
@end@
int err;
/*
* copy index, if provided
*/
if(hdr) {
netsnmp_assert(ctx->index.oids == NULL);
if((hdr->len > MAX_OID_LEN) ||
snmp_clone_mem( (void*)&ctx->index.oids, hdr->oids,
hdr->len * sizeof(oid) )) {
return -1;
}
ctx->index.len = hdr->len;
}
/*
* initialize variable that will hold each component of the index.
* If there are multiple indexes for the table, the variable_lists
* need to be linked together, in order.
*/
@if $ext_index != 0@
/** TODO: add code for external index(s)! */
@end@
@foreach $idx index@
memset( &var_$idx, 0x00, sizeof(var_$idx) );
var_${idx}.type = $idx.type; /* type hint for parse_oid_indexes */
/** TODO: link this index to the next, or NULL for the last one */
#ifdef TABLE_CONTAINER_TODO
snmp_log(LOG_ERR, "${i}_extract_index index list not implemented!\n" );
return 0;
#else
var_${idx}.next_variable = &var_XX;
#endif
@end@
/*
* parse the oid into the individual index components
*/
err = parse_oid_indexes( hdr->oids, hdr->len, &var_$first_idx );
if (err == SNMP_ERR_NOERROR) {
/*
* copy index components into the context structure
*/
@foreach $idx index@
@eval $found = "external"@
@foreach $c column@
@if "$idx" eq "$c"@
@eval $found = "internal"@
@end@
@end@
@if "$found" eq "external"@
/** skipping external index $idx */
@end@
@if "$found" eq "internal"@
@eval $have_type = 0@
@if "$idx.type" eq "ASN_OCTET_STR"@
@eval $have_type = 1@
if(var_${idx}.val_len > sizeof(ctx->$idx))
err = -1;
else
memcpy( ctx->$idx, var_${idx}.val.string, var_${idx}.val_len );
ctx->${idx}_len = var_${idx}.val_len;
@end@
@if "$idx.type" eq "ASN_OBJECT_ID"@
@eval $have_type = 1@
memcpy( ctx->$idx, var_${idx}.val.string, var_${idx}.val_len );
ctx->${idx}_len = var_${idx}.val_len;
@end@
@if $have_type == 0@
ctx->$idx = *var_${idx}.val.integer;
@end@
@end@
@end@
@foreach $c index@
/*
* TODO: check index for valid values. For EXAMPLE:
*
@eval $have_check = 0@
@if "$c.type" eq "ASN_IPADDRESS"@
@eval $have_check = 1@
* if ( XXX_check_ip( *var_${c}.val.integer ) ) {
@end@
@if "$c.type" eq "ASN_OBJECT_ID"@
@eval $have_check = 1@
* if ( XXX_check_oid( var_${c}.val.objid, var_${c}.val_len /
sizeof(oid) ) ) {
@end@
@if "$c.type" eq "ASN_OCTET_STR"@
@eval $have_check = 1@
* if ( XXX_check_value( var_${c}.val.string, XXX ) ) {
@end@
@if $have_check != 1@
* if ( *var_${c}.val.integer != XXX ) {
@end@
* err = -1;
* }
*/
@end@
}
/*
* parsing may have allocated memory. free it.
*/
snmp_reset_var_buffers( &var_$first_idx );
return err;
}
@if "$rs_name" ne ""@
/************************************************************
* the *_can_activate routine is called
* when a row is changed to determine if all the values
* set are consistent with the row's rules for a row status
* of ACTIVE.
*
* return 1 if the row could be ACTIVE
* return 0 if the row is not ready for the ACTIVE state
*/
int ${i}_can_activate(${i}_context *undo_ctx,
${i}_context *row_ctx,
netsnmp_request_group * rg)
{
/*
* TODO: check for activation requirements here
*/
/*
* be optimistic.
*/
return 1;
}
/************************************************************
* the *_can_deactivate routine is called when a row that is
* currently ACTIVE is set to a state other than ACTIVE. If
* there are conditions in which a row should not be allowed
* to transition out of the ACTIVE state (such as the row being
* referred to by another row or table), check for them here.
*
* return 1 if the row can be set to a non-ACTIVE state
* return 0 if the row must remain in the ACTIVE state
*/
int ${i}_can_deactivate(${i}_context *undo_ctx,
${i}_context *row_ctx,
netsnmp_request_group * rg)
{
/*
* TODO: check for deactivation requirements here
*/
return 1;
}
@end@
/************************************************************
* the *_can_delete routine is called to determine if a row
* can be deleted.
*
* return 1 if the row can be deleted
* return 0 if the row cannot be deleted
*/
int ${i}_can_delete(${i}_context *undo_ctx,
${i}_context *row_ctx,
netsnmp_request_group * rg)
{
@if "$rs_name" ne ""@
/*
* probably shouldn't delete a row that we can't
* deactivate.
*/
if(${i}_can_deactivate(undo_ctx,row_ctx,rg) != 1)
return 0;
@end@
/*
* TODO: check for other deletion requirements here
*/
return 1;
}
@if $i.creatable@
/************************************************************
* the *_create_row routine is called by the table handler
* to create a new row for a given index. If you need more
* information (such as column values) to make a decision
* on creating rows, you must create an initial row here
* (to hold the column values), and you can examine the
* situation in more detail in the *_set_reserve1 or later
* states of set processing. Simple check for a NULL undo_ctx
* in those states and do detailed creation checking there.
*
* returns a newly allocated ${i}_context
* structure if the specified indexes are not illegal
* returns NULL for errors or illegal index values.
*/
${i}_context *
${i}_create_row( netsnmp_index* hdr)
{
${i}_context * ctx =
SNMP_MALLOC_TYPEDEF(${i}_context);
if(!ctx)
return NULL;
/*
* TODO: check indexes, if necessary.
*/
if(${i}_extract_index( ctx, hdr )) {
if (NULL != ctx->index.oids)
free(ctx->index.oids);
free(ctx);
return NULL;
}
/* netsnmp_mutex_init(ctx->lock);
netsnmp_mutex_lock(ctx->lock); */
/*
* TODO: initialize any default values here. This is also
* first place you really should allocate any memory for
* yourself to use. If you allocated memory earlier,
* make sure you free it for earlier error cases!
*/
/**
@foreach $c column@
@if $c.settable@
ctx->$c = 0;
@end@
@end@
*/
return ctx;
}
@end@
/************************************************************
* the *_duplicate row routine
*/
${i}_context *
${i}_duplicate_row( ${i}_context * row_ctx)
{
${i}_context * dup;
if(!row_ctx)
return NULL;
dup = SNMP_MALLOC_TYPEDEF(${i}_context);
if(!dup)
return NULL;
if(${i}_row_copy(dup,row_ctx)) {
free(dup);
dup = NULL;
}
return dup;
}
/************************************************************
* the *_delete_row method is called to delete a row.
*/
netsnmp_index * ${i}_delete_row( ${i}_context * ctx )
{
/* netsnmp_mutex_destroy(ctx->lock); */
if(ctx->index.oids)
free(ctx->index.oids);
/*
* TODO: release any memory you allocated here...
*/
/*
* release header
*/
free( ctx );
return NULL;
}
/************************************************************
* RESERVE is used to check the syntax of all the variables
* provided, that the values being set are sensible and consistent,
* and to allocate any resources required for performing the SET.
* After this stage, the expectation is that the set ought to
* succeed, though this is not guaranteed. (In fact, with the UCD
* agent, this is done in two passes - RESERVE1, and
* RESERVE2, to allow for dependancies between variables).
*
* BEFORE calling this routine, the agent will call duplicate_row
* to create a copy of the row (unless this is a new row; i.e.
* row_created == 1).
*
* next state -> SET_RESERVE2 || SET_FREE
*/
void ${i}_set_reserve1( netsnmp_request_group *rg )
{
${i}_context *row_ctx =
(${i}_context *)rg->existing_row;
${i}_context *undo_ctx =
(${i}_context *)rg->undo_info;
netsnmp_variable_list *var;
netsnmp_request_group_item *current;
int rc;
@if "$st_name" ne ""@
/*
* Block all attempts to modify a readOnly row
*/
if( row_ctx && (row_ctx->$st_name == SNMP_STORAGE_READONLY) ) {
netsnmp_set_mode_request_error(MODE_SET_BEGIN, rg->list->ri,
SNMP_ERR_NOTWRITABLE);
return;
}
@end@
/*
* TODO: loop through columns, check syntax and lengths. For
* columns which have no dependencies, you could also move
* the value/range checking here to attempt to catch error
* cases as early as possible.
*/
for( current = rg->list; current; current = current->next ) {
var = current->ri->requestvb;
rc = SNMP_ERR_NOERROR;
switch(current->tri->colnum) {
@foreach $c column@
@if $c.settable@
case COLUMN_$c.uc:
/** $c.syntax = $c.type */
@if $c.needlength@
/* or possibly 'netsnmp_check_vb_type_and_size' */
rc = netsnmp_check_vb_type_and_max_size(var, $c.type,
sizeof(row_ctx->$c));
@else@
/* or possibly 'netsnmp_check_vb_int_range' */
rc = netsnmp_check_vb_int( var );
@end@
break;
@end@
@end@
default: /** We shouldn't get here */
rc = SNMP_ERR_GENERR;
snmp_log(LOG_ERR, "unknown column in "
"${i}_set_reserve1\n");
}
if (rc)
netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc );
rg->status = SNMP_MAX( rg->status, current->ri->status );
}
/*
* done with all the columns. Could check row related
* requirements here.
*/
}
void ${i}_set_reserve2( netsnmp_request_group *rg )
{
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
netsnmp_request_group_item *current;
netsnmp_variable_list *var;
int rc;
rg->rg_void = rg->list->ri;
/*
* TODO: loop through columns, check for valid
* values and any range constraints.
*/
for( current = rg->list; current; current = current->next ) {
var = current->ri->requestvb;
rc = SNMP_ERR_NOERROR;
switch(current->tri->colnum) {
@foreach $c column@
@if $c.settable@
case COLUMN_$c.uc:
/** $c.syntax = $c.type */
@eval $have_check = 0@
@if "$c" eq "$st_name"@
@eval $have_check = 1@
rc = netsnmp_check_vb_storagetype(current->ri->requestvb,
undo_ctx ?
undo_ctx->$c:0);
@end@
@if "$c" eq "$rs_name"@
@eval $have_check = 1@
rc = netsnmp_check_vb_rowstatus(current->ri->requestvb,
undo_ctx ?
undo_ctx->$c:0);
rg->rg_void = current->ri;
@end@
@if "$c.syntax" eq "TruthValue"@
@eval $have_check = 1@
rc = netsnmp_check_vb_truthvalue(current->ri->requestvb);
@end@
@if $have_check == 0@
/*
* TODO: routine to check valid values
*
* EXAMPLE:
*
@if "$c.type" eq "ASN_IPADDRESS"@
@eval $have_check = 1@
* if ( XXX_check_ip( *var->val.integer ) ) {
@end@
@if "$c.type" eq "ASN_OBJECT_ID"@
@eval $have_check = 1@
* if ( XXX_check_oid( var ) ) {
@end@
@if "$c.type" eq "ASN_OCTET_STR"@
@eval $have_check = 1@
* if ( XXX_check_value( var->val.string, XXX ) ) {
@end@
@if $have_check != 1@
* if ( *var->val.integer != XXX ) {
@end@
* rc = SNMP_ERR_INCONSISTENTVALUE;
* rc = SNMP_ERR_BADVALUE;
* }
*/
@end@
break;
@end@
@end@
default: /** We shouldn't get here */
netsnmp_assert(0); /** why wasn't this caught in reserve1? */
}
if (rc)
netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc);
}
/*
* done with all the columns. Could check row related
* requirements here.
*/
}
/************************************************************
* Assuming that the RESERVE phases were successful, the next
* stage is indicated by the action value ACTION. This is used
* to actually implement the set operation. However, this must
* either be done into temporary (persistent) storage, or the
* previous value stored similarly, in case any of the subsequent
* ACTION calls fail.
*
* In your case, changes should be made to row_ctx. A copy of
* the original row is in undo_ctx.
*/
void ${i}_set_action( netsnmp_request_group *rg )
{
netsnmp_variable_list *var;
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
netsnmp_request_group_item *current;
@if "$rs_name" ne ""@
int row_err = 0;
@end@
/*
* TODO: loop through columns, copy varbind values
* to context structure for the row.
*/
for( current = rg->list; current; current = current->next ) {
var = current->ri->requestvb;
switch(current->tri->colnum) {
@foreach $c column@
@if $c.settable@
case COLUMN_$c.uc:
/** $c.syntax = $c.type */
@eval $have_type = 0@
@if "$c.type" eq "ASN_OCTET_STR"@
@eval $have_type = 1@
memcpy(row_ctx->$c,var->val.string,var->val_len);
row_ctx->${c}_len = var->val_len;
@end@
@if "$c.type" eq "ASN_OBJECT_ID"@
@eval $have_type = 1@
memcpy(row_ctx->$c,var->val.objid,var->val_len);
row_ctx->${c}_len = var->val_len;
@end@
@if $have_type == 0@
row_ctx->$c = *var->val.integer;
@end@
break;
@end@
@end@
default: /** We shouldn't get here */
netsnmp_assert(0); /** why wasn't this caught in reserve1? */
}
}
/*
* done with all the columns. Could check row related
* requirements here.
*/
@if "$rs_name" ne ""@
#ifndef ${i}_CAN_MODIFY_ACTIVE_ROW
if( undo_ctx && RS_IS_ACTIVE(undo_ctx->$rs_name) &&
row_ctx && RS_IS_ACTIVE(row_ctx->$rs_name) ) {
row_err = 1;
}
#endif
/*
* check activation/deactivation
*/
row_err = netsnmp_table_array_check_row_status(&cb, rg,
row_ctx ? &row_ctx->$rs_name : NULL,
undo_ctx ? &undo_ctx->$rs_name : NULL);
if(row_err) {
netsnmp_set_mode_request_error(MODE_SET_BEGIN,
(netsnmp_request_info*)rg->rg_void,
row_err);
return;
}
@end@
/*
* TODO: if you have dependencies on other tables, this would be
* a good place to check those, too.
*/
}
/************************************************************
* Only once the ACTION phase has completed successfully, can
* the final COMMIT phase be run. This is used to complete any
* writes that were done into temporary storage, and then release
* any allocated resources. Note that all the code in this phase
* should be "safe" code that cannot possibly fail (cue
* hysterical laughter). The whole intent of the ACTION/COMMIT
* division is that all of the fallible code should be done in
* the ACTION phase, so that it can be backed out if necessary.
*
* BEFORE calling this routine, the agent will update the
* container (inserting a row if row_created == 1, or removing
* the row if row_deleted == 1).
*
* AFTER calling this routine, the agent will delete the
* undo_info.
*/
void ${i}_set_commit( netsnmp_request_group *rg )
{
netsnmp_variable_list *var;
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
netsnmp_request_group_item *current;
/*
* loop through columns
*/
for( current = rg->list; current; current = current->next ) {
var = current->ri->requestvb;
switch(current->tri->colnum) {
@foreach $c column@
@if $c.settable@
case COLUMN_$c.uc:
/** $c.syntax = $c.type */
break;
@end@
@end@
default: /** We shouldn't get here */
netsnmp_assert(0); /** why wasn't this caught in reserve1? */
}
}
/*
* done with all the columns. Could check row related
* requirements here.
*/
}
/************************************************************
* If either of the RESERVE calls fail, the write routines
* are called again with the FREE action, to release any resources
* that have been allocated. The agent will then return a failure
* response to the requesting application.
*
* AFTER calling this routine, the agent will delete undo_info.
*/
void ${i}_set_free( netsnmp_request_group *rg )
{
netsnmp_variable_list *var;
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
netsnmp_request_group_item *current;
/*
* loop through columns
*/
for( current = rg->list; current; current = current->next ) {
var = current->ri->requestvb;
switch(current->tri->colnum) {
@foreach $c column@
@if $c.settable@
case COLUMN_$c.uc:
/** $c.syntax = $c.type */
break;
@end@
@end@
default: /** We shouldn't get here */
/** should have been logged in reserve1 */
}
}
/*
* done with all the columns. Could check row related
* requirements here.
*/
}
/************************************************************
* If the ACTION phase does fail (for example due to an apparently
* valid, but unacceptable value, or an unforeseen problem), then
* the list of write routines are called again, with the UNDO
* action. This requires the routine to reset the value that was
* changed to its previous value (assuming it was actually changed),
* and then to release any resources that had been allocated. As
* with the FREE phase, the agent will then return an indication
* of the error to the requesting application.
*
* BEFORE calling this routine, the agent will update the container
* (remove any newly inserted row, re-insert any removed row).
*
* AFTER calling this routing, the agent will call row_copy
* to restore the data in existing_row from the date in undo_info.
* Then undo_info will be deleted (or existing row, if row_created
* == 1).
*/
void ${i}_set_undo( netsnmp_request_group *rg )
{
netsnmp_variable_list *var;
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
netsnmp_request_group_item *current;
/*
* loop through columns
*/
for( current = rg->list; current; current = current->next ) {
var = current->ri->requestvb;
switch(current->tri->colnum) {
@foreach $c column@
@if $c.settable@
case COLUMN_$c.uc:
/** $c.syntax = $c.type */
break;
@end@
@end@
default: /** We shouldn't get here */
netsnmp_assert(0); /** why wasn't this caught in reserve1? */
}
}
/*
* done with all the columns. Could check row related
* requirements here.
*/
}
@end@
/************************************************************
*
* Initialize the $i table by defining its contents and how it's structured
*/
void
initialize_table_$i(void)
{
netsnmp_table_registration_info *table_info;
if(my_handler) {
snmp_log(LOG_ERR, "initialize_table_${i}_handler called again\n");
return;
}
memset(&cb, 0x00, sizeof(cb));
/** create the table structure itself */
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
my_handler = netsnmp_create_handler_registration("$i",
netsnmp_table_array_helper_handler,
${i}_oid,
${i}_oid_len,
@if $i.settable@
HANDLER_CAN_RWRITE
@else@
HANDLER_CAN_RONLY
@end@
);
if (!my_handler || !table_info) {
snmp_log(LOG_ERR, "malloc failed in "
"initialize_table_${i}_handler\n");
return; /** mallocs failed */
}
/***************************************************
* Setting up the table's definition
*/
/*
* TODO: add any external indexes here.
*/
@if $ext_index != 0@
/** TODO: add code for external index(s)! */
@end@
/*
* internal indexes
*/
@foreach $idx index@
/** index: $idx */
netsnmp_table_helper_add_index(table_info, $idx.type);
@end@
table_info->min_column = ${i}_COL_MIN;
table_info->max_column = ${i}_COL_MAX;
/***************************************************
* registering the table with the master agent
*/
cb.get_value = ${i}_get_value;
cb.container = netsnmp_container_find("${i}_primary:"
"${i}:"
"table_container");
#ifdef ${i}_CUSTOM_SORT
netsnmp_container_add_index(cb.container,
netsnmp_container_find("${i}_custom:"
"${i}:"
"table_container"));
cb.container->next->compare = ${i}_cmp;
#endif
@if $i.settable@
cb.can_set = 1;
@if $i.creatable@
cb.create_row = (UserRowMethod*)${i}_create_row;
@end@
cb.duplicate_row = (UserRowMethod*)${i}_duplicate_row;
cb.delete_row = (UserRowMethod*)${i}_delete_row;
cb.row_copy = (Netsnmp_User_Row_Operation *)${i}_row_copy;
@if "$rs_name" ne ""@
cb.can_activate = (Netsnmp_User_Row_Action *)${i}_can_activate;
cb.can_deactivate = (Netsnmp_User_Row_Action *)${i}_can_deactivate;
@end@
cb.can_delete = (Netsnmp_User_Row_Action *)${i}_can_delete;
cb.set_reserve1 = ${i}_set_reserve1;
cb.set_reserve2 = ${i}_set_reserve2;
cb.set_action = ${i}_set_action;
cb.set_commit = ${i}_set_commit;
cb.set_free = ${i}_set_free;
cb.set_undo = ${i}_set_undo;
@end@
DEBUGMSGTL(("initialize_table_$i",
"Registering table $i "
"as a table array\n"));
netsnmp_table_container_register(my_handler, table_info, &cb,
cb.container, 1);
}
/************************************************************
* ${i}_get_value
*
* This routine is called for get requests to copy the data
* from the context to the varbind for the request. If the
* context has been properly maintained, you don't need to
* change in code in this fuction.
*/
int ${i}_get_value(
netsnmp_request_info *request,
netsnmp_index *item,
netsnmp_table_request_info *table_info )
{
netsnmp_variable_list *var = request->requestvb;
${i}_context *context = (${i}_context *)item;
switch(table_info->colnum) {
@foreach $c column@
@if $c.readable@
@eval $have_type = 0@
case COLUMN_$c.uc:
/** $c.syntax = $c.type */
@if "$c.type" eq "ASN_OBJECT_ID"@
@eval $have_type = 1@
snmp_set_var_typed_value(var, $c.type,
(char*)&context->$c,
context->${c}_len );
@end@
@if "$c.type" eq "ASN_OCTET_STR"@
@eval $have_type = 1@
snmp_set_var_typed_value(var, $c.type,
(char*)&context->$c,
context->${c}_len );
@end@
@if $have_type == 0@
snmp_set_var_typed_value(var, $c.type,
(char*)&context->$c,
sizeof(context->$c) );
@end@
break;
@end@
@end@
default: /** We shouldn't get here */
snmp_log(LOG_ERR, "unknown column in "
"${i}_get_value\n");
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
/************************************************************
* ${i}_get_by_idx
*/
const ${i}_context *
${i}_get_by_idx(netsnmp_index * hdr)
{
return (const ${i}_context *)
CONTAINER_FIND(cb.container, hdr );
}
@end@