3
## For documentation on the code generated by this configuration file,
4
## see the file agent/helpers/table_array.c.
6
######################################################################
8
## @perleval $vars{shortname} =~ s/([A-Z])[a-z]+/$1/g@
9
######################################################################
14
* Note: this file originally auto-generated by mib2c using
15
* $Id: mib2c.array-user.conf,v 5.18.2.2 2004/02/09 18:21:47 rstory Exp $
19
* Yes, there is lots of code here that you might not use. But it is much
20
* easier to remove code than to add it!
30
#include <net-snmp/net-snmp-config.h>
31
#include <net-snmp/library/container.h>
32
#include <net-snmp/agent/table_array.h>
37
@eval $found = "external"@
40
@eval $found = "internal"@
43
/** Index $idx is $found */
44
@if "$found" eq "external"@
50
typedef struct ${i}_context_s {
51
netsnmp_index index; /** THIS MUST BE FIRST!!! */
53
/*************************************************************
54
* You can store data internally in this structure.
56
* TODO: You will probably have to fix a few types here...
59
/** TODO: add storage for external index(s)! */
62
/** $c.syntax = $c.type */
64
@if "$c.type" eq "ASN_OCTET_STR"@
66
@eval $o_len = "65535"@
67
@if "$c.syntax" eq "DisplayString"@
70
@if "$c.syntax" eq "SnmpAdminString"@
73
unsigned char $c[$o_len];
76
@if "$c.type" eq "ASN_OBJECT_ID"@
81
@if "$c.type" eq "ASN_UNSIGNED"@
85
@if "$c.type" eq "ASN_TIMETICKS"@
89
@if "$c.type" eq "ASN_IPADDRESS"@
93
@if "$c.type" eq "ASN_UINTEGER"@
97
@if "$c.type" eq "ASN_INTEGER"@
101
@if "$c.type" eq "ASN_COUNTER"@
102
@eval $have_type = 1@
106
/** TODO: Is this type correct? */
115
* Keep a pointer to your data
120
*add anything else you want here
125
/*************************************************************
126
* function declarations
129
void initialize_table_$i(void);
130
const ${i}_context * ${i}_get_by_idx(netsnmp_index *);
131
const ${i}_context * ${i}_get_by_idx_rs(netsnmp_index *,
133
int ${i}_get_value(netsnmp_request_info *, netsnmp_index *, netsnmp_table_request_info *);
136
/*************************************************************
139
extern oid ${i}_oid[];
140
extern size_t ${i}_oid_len;
142
#define ${i}_TABLE_OID $i.commaoid
144
/*************************************************************
145
* column number definitions for table $i
147
@eval $minv = 0xffffffff@
150
#define COLUMN_$c.uc $c.subid
152
@eval $minv = min($minv, $c.subid)@
153
@eval $maxv = max($maxv, $c.subid)@
155
@if "$c.syntax" eq "RowStatus"@
156
@eval $rs_name = "$c"@
158
@if "$c.syntax" eq "StorageType"@
159
@eval $st_name = "$c"@
162
#define ${i}_COL_MIN $minv
163
#define ${i}_COL_MAX $maxv
165
/* comment out the following line if you don't handle SET-REQUEST for $i */
166
#define ${i}_SET_HANDLING
168
/* comment out the following line if you can't create new rows */
169
#define ${i}_ROW_CREATION
171
/* comment out the following line if you don't want the secondary index */
174
@if "$rs_name" ne ""@
175
/* uncommend the following line if you allow modifications to an
177
/** define ${i}_CAN_MODIFY_ACTIVE_ROW */
180
#ifdef ${i}_SET_HANDLING
182
int ${i}_extract_index( ${i}_context * ctx, netsnmp_index * hdr );
184
void ${i}_set_reserve1( netsnmp_request_group * );
185
void ${i}_set_reserve2( netsnmp_request_group * );
186
void ${i}_set_action( netsnmp_request_group * );
187
void ${i}_set_commit( netsnmp_request_group * );
188
void ${i}_set_free( netsnmp_request_group * );
189
void ${i}_set_undo( netsnmp_request_group * );
191
${i}_context * ${i}_duplicate_row( ${i}_context* );
192
netsnmp_index * ${i}_delete_row( ${i}_context* );
194
@if "$rs_name" ne ""@
195
int ${i}_can_activate(${i}_context *undo_ctx,
196
${i}_context *row_ctx,
197
netsnmp_request_group * rg);
198
int ${i}_can_deactivate(${i}_context *undo_ctx,
199
${i}_context *row_ctx,
200
netsnmp_request_group * rg);
202
int ${i}_can_delete(${i}_context *undo_ctx,
203
${i}_context *row_ctx,
204
netsnmp_request_group * rg);
207
#ifdef ${i}_ROW_CREATION
208
${i}_context * ${i}_create_row( netsnmp_index* );
213
${i}_context * ${i}_get( const char *name, int len );
220
#endif /** $i.uc_H */
222
######################################################################
224
######################################################################
229
* Note: this file originally auto-generated by mib2c using
230
* $Id: mib2c.array-user.conf,v 5.18.2.2 2004/02/09 18:21:47 rstory Exp $
235
* For help understanding NET-SNMP in general, please check the
236
* documentation and FAQ at:
238
* http://www.net-snmp.org/
241
* For help understanding this code, the agent and how it processes
242
* requests, please check the following references.
244
* http://www.net-snmp.org/tutorial-5/
247
* You can also join the #net-snmp channel on irc.freenode.net
248
* and ask for help there.
251
* And if all else fails, send a detailed message to the developers
252
* describing the problem you are having to:
254
* net-snmp-coders@lists.sourceforge.net
257
* Yes, there is lots of code here that you might not use. But it is much
258
* easier to remove code than to add it!
260
#include <net-snmp/net-snmp-config.h>
261
#include <net-snmp/net-snmp-includes.h>
262
#include <net-snmp/agent/net-snmp-agent-includes.h>
264
#include <net-snmp/library/snmp_assert.h>
268
static netsnmp_handler_registration *my_handler = NULL;
269
static netsnmp_table_array_callbacks cb;
271
oid ${i}_oid[] = { ${i}_TABLE_OID };
272
size_t ${i}_oid_len = OID_LENGTH(${i}_oid);
276
/************************************************************
277
* keep binary tree to find context by name
279
static int ${i}_cmp( const void *lhs, const void *rhs );
281
/************************************************************
282
* compare two context pointers here. Return -1 if lhs < rhs,
283
* 0 if lhs == rhs, and 1 if lhs > rhs.
286
${i}_cmp( const void *lhs, const void *rhs )
288
${i}_context *context_l =
290
${i}_context *context_r =
294
* check primary key, then secondary. Add your own code if
295
* there are more than 2 indexes
300
* TODO: implement compare. Remove this ifdef code and
301
* add your own code here.
303
#ifdef TABLE_CONTAINER_TODO
305
"${i}_compare not implemented! Container order undefined\n" );
310
* EXAMPLE (assuming you want to sort on a name):
312
* rc = strcmp( context_l->xxName, context_r->xxName );
317
* TODO: fix secondary keys (or delete if there are none)
319
* if(context_l->yy < context_r->yy)
322
* return (context_l->yy == context_r->yy) ? 0 : 1;
326
/************************************************************
329
/** TODO: set additional indexes as parameters */
331
${i}_get( const char *name, int len )
335
/** we should have a secondary index */
336
netsnmp_assert(cb.container->next != NULL);
339
* TODO: implement compare. Remove this ifdef code and
340
* add your own code here.
342
#ifdef TABLE_CONTAINER_TODO
343
snmp_log(LOG_ERR, "${i}_get not implemented!\n" );
350
* if(len > sizeof(tmp.xxName))
353
* strncpy( tmp.xxName, name, sizeof(tmp.xxName) );
354
* tmp.xxName_len = len;
356
* return CONTAINER_FIND(cb.container->next, &tmp);
362
/************************************************************
363
* Initializes the $i module
368
initialize_table_$i();
371
* TODO: perform any startup stuff here, such as
372
* populating the table with initial data.
374
* ${i}_context * new_row = create_row(index);
375
* CONTAINER_INSERT(cb.container,new_row);
379
/************************************************************
380
* the *_row_copy routine
382
static int ${i}_row_copy(${i}_context * dst,
389
* copy index, if provided
392
free(dst->index.oids);
393
if(snmp_clone_mem( (void*)&dst->index.oids, src->index.oids,
394
src->index.len * sizeof(oid) )) {
395
dst->index.oids = NULL;
398
dst->index.len = src->index.len;
402
* copy components into the context structure
405
/** TODO: add code for external index(s)! */
408
@eval $have_type = 0@
409
@if "$c.type" eq "ASN_OCTET_STR"@
410
@eval $have_type = 1@
411
memcpy( dst->$c, src->$c, src->${c}_len );
412
dst->${c}_len = src->${c}_len;
414
@if "$c.type" eq "ASN_OBJECT_ID"@
415
@eval $have_type = 1@
416
memcpy( src->$c, dst->$c, src->${c}_len );
417
dst->${c}_len = src->${c}_len;
427
#ifdef ${i}_SET_HANDLING
430
* the *_extract_index routine
432
* This routine is called when a set request is received for an index
433
* that was not found in the table container. Here, we parse the oid
434
* in the the individual index components and copy those indexes to the
435
* context. Then we make sure the indexes for the new row are valid.
438
${i}_extract_index( ${i}_context * ctx, netsnmp_index * hdr )
441
* temporary local storage for extracting oid index
443
* extract index uses varbinds (netsnmp_variable_list) to parse
444
* the index OID into the individual components for each index part.
447
/** TODO: add storage for external index(s)! */
449
@eval $first_idx = ""@
451
@if "$first_idx" eq ""@
452
@eval $first_idx = $idx@
454
netsnmp_variable_list var_$idx;
459
* copy index, if provided
462
netsnmp_assert(ctx->index.oids == NULL);
463
if(snmp_clone_mem( (void*)&ctx->index.oids, hdr->oids,
464
hdr->len * sizeof(oid) )) {
467
ctx->index.len = hdr->len;
471
* initialize variable that will hold each component of the index.
472
* If there are multiple indexes for the table, the variable_lists
473
* need to be linked together, in order.
476
/** TODO: add code for external index(s)! */
479
memset( &var_$idx, 0x00, sizeof(var_$idx) );
480
var_${idx}.type = $idx.type; /* type hint for parse_oid_indexes */
481
/** TODO: link this index to the next, or NULL for the last one */
482
#ifdef TABLE_CONTAINER_TODO
483
snmp_log(LOG_ERR, "${i}_extract_index index list not implemented!\n" );
486
var_${idx}.next_variable = &var_XX;
492
* parse the oid into the individual index components
494
err = parse_oid_indexes( hdr->oids, hdr->len, &var_$first_idx );
495
if (err == SNMP_ERR_NOERROR) {
497
* copy index components into the context structure
500
@eval $found = "external"@
503
@eval $found = "internal"@
506
@if "$found" eq "external"@
507
/** skipping external index $idx */
509
@if "$found" eq "internal"@
510
@eval $have_type = 0@
511
@if "$idx.type" eq "ASN_OCTET_STR"@
512
@eval $have_type = 1@
513
if(var_${idx}.val_len > sizeof(ctx->$idx))
516
memcpy( ctx->$idx, var_${idx}.val.string, var_${idx}.val_len );
517
ctx->${idx}_len = var_${idx}.val_len;
519
@if "$idx.type" eq "ASN_OBJECT_ID"@
520
@eval $have_type = 1@
521
memcpy( ctx->$idx, var_${idx}.val.string, var_${idx}.val_len );
522
ctx->${idx}_len = var_${idx}.val_len;
525
ctx->$idx = *var_${idx}.val.integer;
533
* TODO: check index for valid values. For EXAMPLE:
535
@eval $have_check = 0@
536
@if "$c.type" eq "ASN_IPADDRESS"@
537
@eval $have_check = 1@
538
* if ( XXX_check_ip( *var_${c}.val.integer ) ) {
540
@if "$c.type" eq "ASN_OBJECT_ID"@
541
@eval $have_check = 1@
542
* if ( XXX_check_oid( var_${c}.val.objid, var_${c}.val_len /
545
@if "$c.type" eq "ASN_OCTET_STR"@
546
@eval $have_check = 1@
547
* if ( XXX_check_value( var_${c}.val.string, XXX ) ) {
549
@if $have_check != 1@
550
* if ( *var_${c}.val.integer != XXX ) {
559
* parsing may have allocated memory. free it.
561
snmp_reset_var_buffers( &var_$first_idx );
566
@if "$rs_name" ne ""@
567
/************************************************************
568
* the *_can_activate routine is called
569
* when a row is changed to determine if all the values
570
* set are consistent with the row's rules for a row status
573
* return 1 if the row could be ACTIVE
574
* return 0 if the row is not ready for the ACTIVE state
576
int ${i}_can_activate(${i}_context *undo_ctx,
577
${i}_context *row_ctx,
578
netsnmp_request_group * rg)
581
* TODO: check for activation requirements here
591
/************************************************************
592
* the *_can_deactivate routine is called when a row that is
593
* currently ACTIVE is set to a state other than ACTIVE. If
594
* there are conditions in which a row should not be allowed
595
* to transition out of the ACTIVE state (such as the row being
596
* referred to by another row or table), check for them here.
598
* return 1 if the row can be set to a non-ACTIVE state
599
* return 0 if the row must remain in the ACTIVE state
601
int ${i}_can_deactivate(${i}_context *undo_ctx,
602
${i}_context *row_ctx,
603
netsnmp_request_group * rg)
606
* TODO: check for deactivation requirements here
612
/************************************************************
613
* the *_can_delete routine is called to determine if a row
616
* return 1 if the row can be deleted
617
* return 0 if the row cannot be deleted
619
int ${i}_can_delete(${i}_context *undo_ctx,
620
${i}_context *row_ctx,
621
netsnmp_request_group * rg)
623
@if "$rs_name" ne ""@
625
* probably shouldn't delete a row that we can't
628
if(${i}_can_deactivate(undo_ctx,row_ctx,rg) != 1)
633
* TODO: check for other deletion requirements here
638
#ifdef ${i}_ROW_CREATION
639
/************************************************************
640
* the *_create_row routine is called by the table handler
641
* to create a new row for a given index. If you need more
642
* information (such as column values) to make a decision
643
* on creating rows, you must create an initial row here
644
* (to hold the column values), and you can examine the
645
* situation in more detail in the *_set_reserve1 or later
646
* states of set processing. Simple check for a NULL undo_ctx
647
* in those states and do detailed creation checking there.
649
* returns a newly allocated ${i}_context
650
* structure if the specified indexes are not illegal
651
* returns NULL for errors or illegal index values.
654
${i}_create_row( netsnmp_index* hdr)
657
SNMP_MALLOC_TYPEDEF(${i}_context);
662
* TODO: check indexes, if necessary.
664
if(${i}_extract_index( ctx, hdr )) {
665
free(ctx->index.oids);
670
/* netsnmp_mutex_init(ctx->lock);
671
netsnmp_mutex_lock(ctx->lock); */
674
* TODO: initialize any default values here. This is also
675
* first place you really should allocate any memory for
676
* yourself to use. If you allocated memory earlier,
677
* make sure you free it for earlier error cases!
691
/************************************************************
692
* the *_duplicate row routine
695
${i}_duplicate_row( ${i}_context * row_ctx)
702
dup = SNMP_MALLOC_TYPEDEF(${i}_context);
706
if(${i}_row_copy(dup,row_ctx)) {
714
/************************************************************
715
* the *_delete_row method is called to delete a row.
717
netsnmp_index * ${i}_delete_row( ${i}_context * ctx )
719
/* netsnmp_mutex_destroy(ctx->lock); */
722
free(ctx->index.oids);
725
* TODO: release any memory you allocated here...
737
/************************************************************
738
* RESERVE is used to check the syntax of all the variables
739
* provided, that the values being set are sensible and consistent,
740
* and to allocate any resources required for performing the SET.
741
* After this stage, the expectation is that the set ought to
742
* succeed, though this is not guaranteed. (In fact, with the UCD
743
* agent, this is done in two passes - RESERVE1, and
744
* RESERVE2, to allow for dependancies between variables).
746
* BEFORE calling this routine, the agent will call duplicate_row
747
* to create a copy of the row (unless this is a new row; i.e.
750
* next state -> SET_RESERVE2 || SET_FREE
752
void ${i}_set_reserve1( netsnmp_request_group *rg )
754
${i}_context *row_ctx =
755
(${i}_context *)rg->existing_row;
756
${i}_context *undo_ctx =
757
(${i}_context *)rg->undo_info;
758
netsnmp_variable_list *var;
759
netsnmp_request_group_item *current;
762
@if "$st_name" ne ""@
764
* Block all attempts to modify a readOnly row
766
if( row_ctx && (row_ctx->$st_name == SNMP_STORAGE_READONLY) ) {
767
netsnmp_set_mode_request_error(MODE_SET_BEGIN, rg->list->ri,
768
SNMP_ERR_NOTWRITABLE);
774
* TODO: loop through columns, check syntax and lengths. For
775
* columns which have no dependencies, you could also move
776
* the value/range checking here to attempt to catch error
777
* cases as early as possible.
779
for( current = rg->list; current; current = current->next ) {
781
var = current->ri->requestvb;
782
rc = SNMP_ERR_NOERROR;
784
switch(current->tri->colnum) {
789
/** $c.syntax = $c.type */
790
rc = netsnmp_check_vb_type_and_size(var, $c.type,
791
sizeof(row_ctx->$c));
796
default: /** We shouldn't get here */
797
rc = SNMP_ERR_GENERR;
798
snmp_log(LOG_ERR, "unknown column in "
799
"${i}_set_reserve1\n");
803
netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc );
804
rg->status = SNMP_MAX( rg->status, current->ri->status );
808
* done with all the columns. Could check row related
813
void ${i}_set_reserve2( netsnmp_request_group *rg )
815
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
816
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
817
netsnmp_request_group_item *current;
818
netsnmp_variable_list *var;
821
rg->rg_void = rg->list->ri;
824
* TODO: loop through columns, check for valid
825
* values and any range constraints.
827
for( current = rg->list; current; current = current->next ) {
829
var = current->ri->requestvb;
830
rc = SNMP_ERR_NOERROR;
832
switch(current->tri->colnum) {
837
/** $c.syntax = $c.type */
838
@eval $have_check = 0@
839
@if "$c" eq "$st_name"@
840
@eval $have_check = 1@
841
rc = netsnmp_check_vb_storagetype(current->ri->requestvb,
845
@if "$c" eq "$rs_name"@
846
@eval $have_check = 1@
847
rc = netsnmp_check_vb_rowstatus(current->ri->requestvb,
850
rg->rg_void = current->ri;
852
@if "$c.syntax" eq "TruthValue"@
853
@eval $have_check = 1@
854
rc = netsnmp_check_vb_truthvalue(current->ri->requestvb);
856
@if $have_check == 0@
858
* TODO: routine to check valid values
862
@if "$c.type" eq "ASN_IPADDRESS"@
863
@eval $have_check = 1@
864
* if ( XXX_check_ip( *var->val.integer ) ) {
866
@if "$c.type" eq "ASN_OBJECT_ID"@
867
@eval $have_check = 1@
868
* if ( XXX_check_oid( var ) ) {
870
@if "$c.type" eq "ASN_OCTET_STR"@
871
@eval $have_check = 1@
872
* if ( XXX_check_value( var->val.string, XXX ) ) {
874
@if $have_check != 1@
875
* if ( *var->val.integer != XXX ) {
877
* rc = SNMP_ERR_INCONSISTENTVALUE;
878
* rc = SNMP_ERR_BADVALUE;
886
default: /** We shouldn't get here */
887
netsnmp_assert(0); /** why wasn't this caught in reserve1? */
891
netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc);
895
* done with all the columns. Could check row related
900
/************************************************************
901
* Assuming that the RESERVE phases were successful, the next
902
* stage is indicated by the action value ACTION. This is used
903
* to actually implement the set operation. However, this must
904
* either be done into temporary (persistent) storage, or the
905
* previous value stored similarly, in case any of the subsequent
908
* In your case, changes should be made to row_ctx. A copy of
909
* the original row is in undo_ctx.
911
void ${i}_set_action( netsnmp_request_group *rg )
913
netsnmp_variable_list *var;
914
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
915
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
916
netsnmp_request_group_item *current;
918
@if "$rs_name" ne ""@
923
* TODO: loop through columns, copy varbind values
924
* to context structure for the row.
926
for( current = rg->list; current; current = current->next ) {
928
var = current->ri->requestvb;
930
switch(current->tri->colnum) {
935
/** $c.syntax = $c.type */
936
@eval $have_type = 0@
937
@if "$c.type" eq "ASN_OCTET_STR"@
938
@eval $have_type = 1@
939
memcpy(row_ctx->$c,var->val.string,var->val_len);
940
row_ctx->${c}_len = var->val_len;
942
@if "$c.type" eq "ASN_OBJECT_ID"@
943
@eval $have_type = 1@
944
memcpy(row_ctx->$c,var->val.objid,var->val_len);
945
row_ctx->${c}_len = var->val_len;
948
row_ctx->$c = *var->val.integer;
954
default: /** We shouldn't get here */
955
netsnmp_assert(0); /** why wasn't this caught in reserve1? */
960
* done with all the columns. Could check row related
963
@if "$rs_name" ne ""@
964
#ifndef ${i}_CAN_MODIFY_ACTIVE_ROW
965
if( undo_ctx && RS_IS_ACTIVE(undo_ctx->$rs_name) &&
966
row_ctx && RS_IS_ACTIVE(row_ctx->$rs_name) ) {
972
* check activation/deactivation
974
row_err = netsnmp_table_array_check_row_status(&cb, rg,
975
row_ctx ? &row_ctx->$rs_name : NULL,
976
undo_ctx ? &undo_ctx->$rs_name : NULL);
978
netsnmp_set_mode_request_error(MODE_SET_BEGIN,
979
(netsnmp_request_info*)rg->rg_void,
986
* TODO: if you have dependencies on other tables, this would be
987
* a good place to check those, too.
991
/************************************************************
992
* Only once the ACTION phase has completed successfully, can
993
* the final COMMIT phase be run. This is used to complete any
994
* writes that were done into temporary storage, and then release
995
* any allocated resources. Note that all the code in this phase
996
* should be "safe" code that cannot possibly fail (cue
997
* hysterical laughter). The whole intent of the ACTION/COMMIT
998
* division is that all of the fallible code should be done in
999
* the ACTION phase, so that it can be backed out if necessary.
1001
* BEFORE calling this routine, the agent will update the
1002
* container (inserting a row if row_created == 1, or removing
1003
* the row if row_deleted == 1).
1005
* AFTER calling this routine, the agent will delete the
1008
void ${i}_set_commit( netsnmp_request_group *rg )
1010
netsnmp_variable_list *var;
1011
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
1012
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
1013
netsnmp_request_group_item *current;
1016
* loop through columns
1018
for( current = rg->list; current; current = current->next ) {
1020
var = current->ri->requestvb;
1022
switch(current->tri->colnum) {
1027
/** $c.syntax = $c.type */
1032
default: /** We shouldn't get here */
1033
netsnmp_assert(0); /** why wasn't this caught in reserve1? */
1038
* done with all the columns. Could check row related
1039
* requirements here.
1043
/************************************************************
1044
* If either of the RESERVE calls fail, the write routines
1045
* are called again with the FREE action, to release any resources
1046
* that have been allocated. The agent will then return a failure
1047
* response to the requesting application.
1049
* AFTER calling this routine, the agent will delete undo_info.
1051
void ${i}_set_free( netsnmp_request_group *rg )
1053
netsnmp_variable_list *var;
1054
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
1055
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
1056
netsnmp_request_group_item *current;
1059
* loop through columns
1061
for( current = rg->list; current; current = current->next ) {
1063
var = current->ri->requestvb;
1065
switch(current->tri->colnum) {
1070
/** $c.syntax = $c.type */
1075
default: /** We shouldn't get here */
1076
/** should have been logged in reserve1 */
1081
* done with all the columns. Could check row related
1082
* requirements here.
1086
/************************************************************
1087
* If the ACTION phase does fail (for example due to an apparently
1088
* valid, but unacceptable value, or an unforeseen problem), then
1089
* the list of write routines are called again, with the UNDO
1090
* action. This requires the routine to reset the value that was
1091
* changed to its previous value (assuming it was actually changed),
1092
* and then to release any resources that had been allocated. As
1093
* with the FREE phase, the agent will then return an indication
1094
* of the error to the requesting application.
1096
* BEFORE calling this routine, the agent will update the container
1097
* (remove any newly inserted row, re-insert any removed row).
1099
* AFTER calling this routing, the agent will call row_copy
1100
* to restore the data in existing_row from the date in undo_info.
1101
* Then undo_info will be deleted (or existing row, if row_created
1104
void ${i}_set_undo( netsnmp_request_group *rg )
1106
netsnmp_variable_list *var;
1107
${i}_context *row_ctx = (${i}_context *)rg->existing_row;
1108
${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
1109
netsnmp_request_group_item *current;
1112
* loop through columns
1114
for( current = rg->list; current; current = current->next ) {
1116
var = current->ri->requestvb;
1118
switch(current->tri->colnum) {
1123
/** $c.syntax = $c.type */
1128
default: /** We shouldn't get here */
1129
netsnmp_assert(0); /** why wasn't this caught in reserve1? */
1134
* done with all the columns. Could check row related
1135
* requirements here.
1139
#endif /** ${i}_SET_HANDLING */
1142
/************************************************************
1144
* Initialize the $i table by defining its contents and how it's structured
1147
initialize_table_$i(void)
1149
netsnmp_table_registration_info *table_info;
1152
snmp_log(LOG_ERR, "initialize_table_${i}_handler called again\n");
1156
memset(&cb, 0x00, sizeof(cb));
1158
/** create the table structure itself */
1159
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
1161
/* if your table is read only, it's easiest to change the
1162
HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY */
1163
my_handler = netsnmp_create_handler_registration("$i",
1164
netsnmp_table_array_helper_handler,
1167
HANDLER_CAN_RWRITE);
1169
if (!my_handler || !table_info) {
1170
snmp_log(LOG_ERR, "malloc failed in "
1171
"initialize_table_${i}_handler\n");
1172
return; /** mallocs failed */
1175
/***************************************************
1176
* Setting up the table's definition
1179
* TODO: add any external indexes here.
1181
@if $ext_index != 0@
1182
/** TODO: add code for external index(s)! */
1188
@foreach $idx index@
1190
netsnmp_table_helper_add_index(table_info, $idx.type);
1193
table_info->min_column = ${i}_COL_MIN;
1194
table_info->max_column = ${i}_COL_MAX;
1196
/***************************************************
1197
* registering the table with the master agent
1199
cb.get_value = ${i}_get_value;
1200
cb.container = netsnmp_container_find("${i}_primary:"
1204
netsnmp_container_add_index(cb.container,
1205
netsnmp_container_find("${i}_secondary:"
1207
"table_container"));
1208
cb.container->next->compare = ${i}_cmp;
1210
#ifdef ${i}_SET_HANDLING
1212
#ifdef ${i}_ROW_CREATION
1213
cb.create_row = (UserRowMethod*)${i}_create_row;
1215
cb.duplicate_row = (UserRowMethod*)${i}_duplicate_row;
1216
cb.delete_row = (UserRowMethod*)${i}_delete_row;
1217
cb.row_copy = (Netsnmp_User_Row_Operation *)${i}_row_copy;
1219
@if "$rs_name" ne ""@
1220
cb.can_activate = (Netsnmp_User_Row_Action *)${i}_can_activate;
1221
cb.can_deactivate = (Netsnmp_User_Row_Action *)${i}_can_deactivate;
1223
cb.can_delete = (Netsnmp_User_Row_Action *)${i}_can_delete;
1225
cb.set_reserve1 = ${i}_set_reserve1;
1226
cb.set_reserve2 = ${i}_set_reserve2;
1227
cb.set_action = ${i}_set_action;
1228
cb.set_commit = ${i}_set_commit;
1229
cb.set_free = ${i}_set_free;
1230
cb.set_undo = ${i}_set_undo;
1232
DEBUGMSGTL(("initialize_table_$i",
1233
"Registering table $i "
1234
"as a table array\n"));
1235
netsnmp_table_container_register(my_handler, table_info, &cb,
1239
/************************************************************
1242
* This routine is called for get requests to copy the data
1243
* from the context to the varbind for the request. If the
1244
* context has been properly maintained, you don't need to
1245
* change in code in this fuction.
1248
netsnmp_request_info *request,
1249
netsnmp_index *item,
1250
netsnmp_table_request_info *table_info )
1252
netsnmp_variable_list *var = request->requestvb;
1253
${i}_context *context = (${i}_context *)item;
1255
switch(table_info->colnum) {
1258
@eval $have_type = 0@
1260
/** $c.syntax = $c.type */
1261
@if "$c.type" eq "ASN_OBJECT_ID"@
1262
@eval $have_type = 1@
1263
snmp_set_var_typed_value(var, $c.type,
1264
(char*)&context->$c,
1265
context->${c}_len );
1267
@if "$c.type" eq "ASN_OCTET_STR"@
1268
@eval $have_type = 1@
1269
snmp_set_var_typed_value(var, $c.type,
1270
(char*)&context->$c,
1271
context->${c}_len );
1273
@if $have_type == 0@
1274
snmp_set_var_typed_value(var, $c.type,
1275
(char*)&context->$c,
1276
sizeof(context->$c) );
1281
default: /** We shouldn't get here */
1282
snmp_log(LOG_ERR, "unknown column in "
1283
"${i}_get_value\n");
1284
return SNMP_ERR_GENERR;
1286
return SNMP_ERR_NOERROR;
1289
/************************************************************
1292
const ${i}_context *
1293
${i}_get_by_idx(netsnmp_index * hdr)
1295
return (const ${i}_context *)
1296
CONTAINER_FIND(cb.container, hdr );