diff options
Diffstat (limited to 'local/mib2c.array-user.conf')
-rw-r--r-- | local/mib2c.array-user.conf | 1305 |
1 files changed, 1305 insertions, 0 deletions
diff --git a/local/mib2c.array-user.conf b/local/mib2c.array-user.conf new file mode 100644 index 0000000..31559ac --- /dev/null +++ b/local/mib2c.array-user.conf @@ -0,0 +1,1305 @@ +## -*- 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@ |