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 1.1.1.1 2005/04/29 01:45:17 echo 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 1.1.1.1 2005/04/29 01:45:17 echo 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/
247 * You can also join the #net-snmp channel on irc.openprojects.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" );
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
375 /************************************************************
376 * the *_row_copy routine
378 static int ${i}_row_copy(${i}_context * dst,
385 * copy index, if provided
388 free(dst->index.oids);
389 if(snmp_clone_mem( (void*)&dst->index.oids, src->index.oids,
390 src->index.len * sizeof(oid) )) {
391 dst->index.oids = NULL;
394 dst->index.len = src->index.len;
398 * copy components into the context structure
401 /** TODO: add code for external index(s)! */
404 @eval $have_type = 0@
405 @if "$c.type" eq "ASN_OCTET_STR"@
406 @eval $have_type = 1@
407 memcpy( dst->$c, src->$c, src->${c}_len );
408 dst->${c}_len = src->${c}_len;
410 @if "$c.type" eq "ASN_OBJECT_ID"@
411 @eval $have_type = 1@
412 memcpy( src->$c, dst->$c, src->${c}_len );
413 dst->${c}_len = src->${c}_len;
423 #ifdef ${i}_SET_HANDLING
426 * the *_extract_index routine
429 ${i}_extract_index( ${i}_context * ctx, netsnmp_index * hdr )
432 * temporary local storage for extracting oid index
435 /** TODO: add storage for external index(s)! */
437 @eval $first_idx = ""@
439 @if "$first_idx" eq ""@
440 @eval $first_idx = $idx@
442 netsnmp_variable_list var_$idx;
447 * copy index, if provided
450 netsnmp_assert(ctx->index.oids == NULL);
451 if(snmp_clone_mem( (void*)&ctx->index.oids, hdr->oids,
452 hdr->len * sizeof(oid) )) {
455 ctx->index.len = hdr->len;
459 * Create variable to hold each component of the index
462 /** TODO: add code for external index(s)! */
465 memset( &var_$idx, 0x00, sizeof(var_$idx) );
466 var_${idx}.type = $idx.type;
467 /** TODO: link this index to the next, or NULL for the last one */
468 #ifdef TABLE_CONTAINER_TODO
469 snmp_log(LOG_ERR, "${i}_extract_index index list not implemented!\n" );
472 var_$idx.next_variable = &var_XX;
478 * parse the oid into the individual components
480 err = parse_oid_indexes( hdr->oids, hdr->len, &var_$first_idx );
481 if (err == SNMP_ERR_NOERROR) {
483 * copy components into the context structure
486 @eval $found = "external"@
489 @eval $found = "internal"@
492 @if "$found" eq "external"@
493 /** skipping external index $idx */
495 @if "$found" eq "internal"@
496 @eval $have_type = 0@
497 @if "$idx.type" eq "ASN_OCTET_STR"@
498 @eval $have_type = 1@
499 if(var_$idx.val_len > sizeof(ctx->$idx))
502 memcpy( ctx->$idx, var_$idx.val.string, var_$idx.val_len );
503 ctx->${idx}_len = var_$idx.val_len;
505 @if "$idx.type" eq "ASN_OBJECT_ID"@
506 @eval $have_type = 1@
507 memcpy( ctx->$idx, var_$idx.val.string, var_$idx.val_len );
508 ctx->$idx_len = var_$idx.val_len;
511 ctx->$idx = *var_$idx.val.integer;
519 * TODO: check index for valid values. For EXAMPLE:
521 @eval $have_check = 0@
522 @if "$c.type" eq "ASN_IPADDRESS"@
523 @eval $have_check = 1@
524 * if ( XXX_check_ip( *var_$c.val.integer ) ) {
526 @if "$c.type" eq "ASN_OBJECT_ID"@
527 @eval $have_check = 1@
528 * if ( XXX_check_oid( var_$c.val.objid, var_$c.val_len /
531 @if "$c.type" eq "ASN_OCTET_STR"@
532 @eval $have_check = 1@
533 * if ( XXX_check_value( var_$c.val.string, XXX ) ) {
535 @if $have_check != 1@
536 * if ( *var_$c.val.integer != XXX ) {
545 * parsing may have allocated memory. free it.
547 snmp_reset_var_buffers( &var_$first_idx );
552 @if "$rs_name" ne ""@
553 /************************************************************
554 * the *_can_activate routine is called
555 * when a row is changed to determine if all the values
556 * set are consistent with the row's rules for a row status
559 * return 1 if the row could be ACTIVE
560 * return 0 if the row is not ready for the ACTIVE state
562 int ${i}_can_activate(${i}_context *undo_ctx,
563 ${i}_context *row_ctx,
564 netsnmp_request_group * rg)
567 * TODO: check for activation requirements here
572 /************************************************************
573 * the *_can_deactivate routine is called when a row that is
574 * currently ACTIVE is set to a state other than ACTIVE. If
575 * there are conditions in which a row should not be allowed
576 * to transition out of the ACTIVE state (such as the row being
577 * referred to by another row or table), check for them here.
579 * return 1 if the row can be set to a non-ACTIVE state
580 * return 0 if the row must remain in the ACTIVE state
582 int ${i}_can_deactivate(${i}_context *undo_ctx,
583 ${i}_context *row_ctx,
584 netsnmp_request_group * rg)
587 * TODO: check for deactivation requirements here
593 /************************************************************
594 * the *_can_delete routine is called to determine if a row
597 * return 1 if the row can be deleted
598 * return 0 if the row cannot be deleted
600 int ${i}_can_delete(${i}_context *undo_ctx,
601 ${i}_context *row_ctx,
602 netsnmp_request_group * rg)
604 @if "$rs_name" ne ""@
606 * probably shouldn't delete a row that we can't
609 if(${i}_can_deactivate(undo_ctx,row_ctx,rg) != 1)
614 * TODO: check for other deletion requirements here
619 #ifdef ${i}_ROW_CREATION
620 /************************************************************
621 * the *_create_row routine is called by the table handler
622 * to create a new row for a given index. If you need more
623 * information (such as column values) to make a decision
624 * on creating rows, you must create an initial row here
625 * (to hold the column values), and you can examine the
626 * situation in more detail in the *_set_reserve1 or later
627 * states of set processing. Simple check for a NULL undo_ctx
628 * in those states and do detailed creation checking there.
630 * returns a newly allocated ${i}_context
631 * structure if the specified indexes are not illegal
632 * returns NULL for errors or illegal index values.
635 ${i}_create_row( netsnmp_index* hdr)
638 SNMP_MALLOC_TYPEDEF(${i}_context);
643 * TODO: check indexes, if necessary.
645 if(${i}_extract_index( ctx, hdr )) {
646 free(ctx->index.oids);
651 /* netsnmp_mutex_init(ctx->lock);
652 netsnmp_mutex_lock(ctx->lock); */
655 * TODO: initialize any default values here. This is also
656 * first place you really should allocate any memory for
657 * yourself to use. If you allocated memory earlier,
658 * make sure you free it for earlier error cases!
672 /************************************************************
673 * the *_duplicate row routine
676 ${i}_duplicate_row( ${i}_context * row_ctx)
683 dup = SNMP_MALLOC_TYPEDEF(${i}_context);
687 if(${i}_row_copy(dup,row_ctx)) {
695 /************************************************************
696 * the *_delete_row method is called to delete a row.
698 netsnmp_index * ${i}_delete_row( ${i}_context * ctx )
700 /* netsnmp_mutex_destroy(ctx->lock); */
703 free(ctx->index.oids);
706 * TODO: release any memory you allocated here...
718 /************************************************************
719 * RESERVE is used to check the syntax of all the variables
720 * provided, that the values being set are sensible and consistent,
721 * and to allocate any resources required for performing the SET.
722 * After this stage, the expectation is that the set ought to
723 * succeed, though this is not guaranteed. (In fact, with the UCD
724 * agent, this is done in two passes - RESERVE1, and
725 * RESERVE2, to allow for dependancies between variables).
727 * BEFORE calling this routine, the agent will call duplicate_row
728 * to create a copy of the row (unless this is a new row; i.e.
731 * next state -> SET_RESERVE2 || SET_FREE
733 void ${i}_set_reserve1( netsnmp_request_group *rg )
735 ${i}_context *row_ctx =
736 (${i}_context *)rg->existing_row;
737 ${i}_context *undo_ctx =
738 (${i}_context *)rg->undo_info;
739 netsnmp_variable_list *var;
740 netsnmp_request_group_item *current;
743 @if "$st_name" ne ""@
745 * Block all attempts to modify a readOnly row
747 if( row_ctx && (row_ctx->$st_name == SNMP_STORAGE_READONLY) ) {
748 netsnmp_set_mode_request_error(MODE_SET_BEGIN, rg->list->ri,
749 SNMP_ERR_NOTWRITABLE);
755 * TODO: loop through columns, check syntax and lengths. For
756 * columns which have no dependencies, you could also move
757 * the value/range checking here to attempt to catch error
758 * cases as early as possible.
760 for( current = rg->list; current; current = current->next ) {
762 var = current->ri->requestvb;
763 rc = SNMP_ERR_NOERROR;
765 switch(current->tri->colnum) {
770 /** $c.syntax = $c.type */
771 rc = netsnmp_check_vb_type_and_size(var, $c.type,
772 sizeof(row_ctx->$c));
777 default: /** We shouldn't get here */
778 rc = SNMP_ERR_GENERR;
779 snmp_log(LOG_ERR, "unknown column in "
780 "${i}_set_reserve1\n");
784 netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc );
785 rg->status = SNMP_MAX( rg->status, current->ri->status );
789 * done with all the columns. Could check row related
794 void ${i}_set_reserve2( netsnmp_request_group *rg )
796 ${i}_context *row_ctx = (${i}_context *)rg->existing_row;
797 ${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
798 netsnmp_request_group_item *current;
799 netsnmp_variable_list *var;
802 rg->rg_void = rg->list->ri;
805 * TODO: loop through columns, check for valid
806 * values and any range constraints.
808 for( current = rg->list; current; current = current->next ) {
810 var = current->ri->requestvb;
811 rc = SNMP_ERR_NOERROR;
813 switch(current->tri->colnum) {
818 /** $c.syntax = $c.type */
819 @eval $have_check = 0@
820 @if "$c" eq "$st_name"@
821 @eval $have_check = 1@
822 rc = netsnmp_check_vb_storagetype(current->ri->requestvb,
826 @if "$c" eq "$rs_name"@
827 @eval $have_check = 1@
828 rc = netsnmp_check_vb_rowstatus(current->ri->requestvb,
831 rg->rg_void = current->ri;
833 @if "$c.syntax" eq "TruthValue"@
834 @eval $have_check = 1@
835 rc = netsnmp_check_vb_truthvalue(current->ri->requestvb);
837 @if $have_check == 0@
839 * TODO: routine to check valid values
843 @if "$c.type" eq "ASN_IPADDRESS"@
844 @eval $have_check = 1@
845 * if ( XXX_check_ip( *var->val.integer ) ) {
847 @if "$c.type" eq "ASN_OBJECT_ID"@
848 @eval $have_check = 1@
849 * if ( XXX_check_oid( var ) ) {
851 @if "$c.type" eq "ASN_OCTET_STR"@
852 @eval $have_check = 1@
853 * if ( XXX_check_value( var->val.string, XXX ) ) {
855 @if $have_check != 1@
856 * if ( *var->val.integer != XXX ) {
858 * rc = SNMP_ERR_INCONSISTENTVALUE;
859 * rc = SNMP_ERR_BADVALUE;
867 default: /** We shouldn't get here */
868 netsnmp_assert(0); /** why wasn't this caught in reserve1? */
872 netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc);
876 * done with all the columns. Could check row related
881 /************************************************************
882 * Assuming that the RESERVE phases were successful, the next
883 * stage is indicated by the action value ACTION. This is used
884 * to actually implement the set operation. However, this must
885 * either be done into temporary (persistent) storage, or the
886 * previous value stored similarly, in case any of the subsequent
889 * In your case, changes should be made to row_ctx. A copy of
890 * the original row is in undo_ctx.
892 void ${i}_set_action( netsnmp_request_group *rg )
894 netsnmp_variable_list *var;
895 ${i}_context *row_ctx = (${i}_context *)rg->existing_row;
896 ${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
897 netsnmp_request_group_item *current;
899 @if "$rs_name" ne ""@
904 * TODO: loop through columns, copy varbind values
905 * to context structure for the row.
907 for( current = rg->list; current; current = current->next ) {
909 var = current->ri->requestvb;
911 switch(current->tri->colnum) {
916 /** $c.syntax = $c.type */
917 @eval $have_type = 0@
918 @if "$c.type" eq "ASN_OCTET_STR"@
919 @eval $have_type = 1@
920 memcpy(row_ctx->$c,var->val.string,var->val_len);
921 row_ctx->${c}_len = var->val_len;
923 @if "$c.type" eq "ASN_OBJECT_ID"@
924 @eval $have_type = 1@
925 memcpy(row_ctx->$c,var->val.objid,var->val_len);
926 row_ctx->${c}_len = var->val_len;
929 row_ctx->$c = *var->val.integer;
935 default: /** We shouldn't get here */
936 netsnmp_assert(0); /** why wasn't this caught in reserve1? */
941 * done with all the columns. Could check row related
944 @if "$rs_name" ne ""@
945 #ifndef ${i}_CAN_MODIFY_ACTIVE_ROW
946 if( undo_ctx && RS_IS_ACTIVE(undo_ctx->$rs_name) &&
947 row_ctx && RS_IS_ACTIVE(row_ctx->$rs_name) ) {
953 * check activation/deactivation
955 row_err = netsnmp_table_array_check_row_status(&cb, rg,
956 row_ctx ? &row_ctx->$rs_name : NULL,
957 undo_ctx ? &undo_ctx->$rs_name : NULL);
959 netsnmp_set_mode_request_error(MODE_SET_BEGIN,
960 (netsnmp_request_info*)rg->rg_void,
967 * TODO: if you have dependencies on other tables, this would be
968 * a good place to check those, too.
972 /************************************************************
973 * Only once the ACTION phase has completed successfully, can
974 * the final COMMIT phase be run. This is used to complete any
975 * writes that were done into temporary storage, and then release
976 * any allocated resources. Note that all the code in this phase
977 * should be "safe" code that cannot possibly fail (cue
978 * hysterical laughter). The whole intent of the ACTION/COMMIT
979 * division is that all of the fallible code should be done in
980 * the ACTION phase, so that it can be backed out if necessary.
982 * BEFORE calling this routine, the agent will update the
983 * container (inserting a row if row_created == 1, or removing
984 * the row if row_deleted == 1).
986 * AFTER calling this routine, the agent will delete the
989 void ${i}_set_commit( netsnmp_request_group *rg )
991 netsnmp_variable_list *var;
992 ${i}_context *row_ctx = (${i}_context *)rg->existing_row;
993 ${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
994 netsnmp_request_group_item *current;
997 * loop through columns
999 for( current = rg->list; current; current = current->next ) {
1001 var = current->ri->requestvb;
1003 switch(current->tri->colnum) {
1008 /** $c.syntax = $c.type */
1013 default: /** We shouldn't get here */
1014 netsnmp_assert(0); /** why wasn't this caught in reserve1? */
1019 * done with all the columns. Could check row related
1020 * requirements here.
1024 /************************************************************
1025 * If either of the RESERVE calls fail, the write routines
1026 * are called again with the FREE action, to release any resources
1027 * that have been allocated. The agent will then return a failure
1028 * response to the requesting application.
1030 * AFTER calling this routine, the agent will delete undo_info.
1032 void ${i}_set_free( netsnmp_request_group *rg )
1034 netsnmp_variable_list *var;
1035 ${i}_context *row_ctx = (${i}_context *)rg->existing_row;
1036 ${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
1037 netsnmp_request_group_item *current;
1040 * loop through columns
1042 for( current = rg->list; current; current = current->next ) {
1044 var = current->ri->requestvb;
1046 switch(current->tri->colnum) {
1051 /** $c.syntax = $c.type */
1056 default: /** We shouldn't get here */
1057 /** should have been logged in reserve1 */
1062 * done with all the columns. Could check row related
1063 * requirements here.
1067 /************************************************************
1068 * If the ACTION phase does fail (for example due to an apparently
1069 * valid, but unacceptable value, or an unforeseen problem), then
1070 * the list of write routines are called again, with the UNDO
1071 * action. This requires the routine to reset the value that was
1072 * changed to its previous value (assuming it was actually changed),
1073 * and then to release any resources that had been allocated. As
1074 * with the FREE phase, the agent will then return an indication
1075 * of the error to the requesting application.
1077 * BEFORE calling this routine, the agent will update the container
1078 * (remove any newly inserted row, re-insert any removed row).
1080 * AFTER calling this routing, the agent will call row_copy
1081 * to restore the data in existing_row from the date in undo_info.
1082 * Then undo_info will be deleted (or existing row, if row_created
1085 void ${i}_set_undo( netsnmp_request_group *rg )
1087 netsnmp_variable_list *var;
1088 ${i}_context *row_ctx = (${i}_context *)rg->existing_row;
1089 ${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
1090 netsnmp_request_group_item *current;
1093 * loop through columns
1095 for( current = rg->list; current; current = current->next ) {
1097 var = current->ri->requestvb;
1099 switch(current->tri->colnum) {
1104 /** $c.syntax = $c.type */
1109 default: /** We shouldn't get here */
1110 netsnmp_assert(0); /** why wasn't this caught in reserve1? */
1115 * done with all the columns. Could check row related
1116 * requirements here.
1120 #endif /** ${i}_SET_HANDLING */
1123 /************************************************************
1125 * Initialize the $i table by defining its contents and how it's structured
1128 initialize_table_$i(void)
1130 netsnmp_table_registration_info *table_info;
1133 snmp_log(LOG_ERR, "initialize_table_${i}_handler called again\n");
1137 memset(&cb, 0x00, sizeof(cb));
1139 /** create the table structure itself */
1140 table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
1142 /* if your table is read only, it's easiest to change the
1143 HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY */
1144 my_handler = netsnmp_create_handler_registration("$i",
1145 netsnmp_table_array_helper_handler,
1148 HANDLER_CAN_RWRITE);
1150 if (!my_handler || !table_info) {
1151 snmp_log(LOG_ERR, "malloc failed in "
1152 "initialize_table_${i}_handler\n");
1153 return; /** mallocs failed */
1156 /***************************************************
1157 * Setting up the table's definition
1160 * TODO: add any external indexes here.
1162 @if $ext_index != 0@
1163 /** TODO: add code for external index(s)! */
1169 @foreach $idx index@
1171 netsnmp_table_helper_add_index(table_info, $idx.type);
1174 table_info->min_column = ${i}_COL_MIN;
1175 table_info->max_column = ${i}_COL_MAX;
1177 /***************************************************
1178 * registering the table with the master agent
1180 cb.get_value = ${i}_get_value;
1181 cb.container = netsnmp_container_find("${i}_primary:"
1185 netsnmp_container_add_index(cb.container,
1186 netsnmp_container_find("${i}_secondary:"
1188 "table_container"));
1189 cb.container->next->compare = ${i}_cmp;
1191 #ifdef ${i}_SET_HANDLING
1193 #ifdef ${i}_ROW_CREATION
1194 cb.create_row = (UserRowMethod*)${i}_create_row;
1196 cb.duplicate_row = (UserRowMethod*)${i}_duplicate_row;
1197 cb.delete_row = (UserRowMethod*)${i}_delete_row;
1198 cb.row_copy = (Netsnmp_User_Row_Operation *)${i}_row_copy;
1200 @if "$rs_name" ne ""@
1201 cb.can_activate = (Netsnmp_User_Row_Action *)${i}_can_activate;
1202 cb.can_deactivate = (Netsnmp_User_Row_Action *)${i}_can_deactivate;
1204 cb.can_delete = (Netsnmp_User_Row_Action *)${i}_can_delete;
1206 cb.set_reserve1 = ${i}_set_reserve1;
1207 cb.set_reserve2 = ${i}_set_reserve2;
1208 cb.set_action = ${i}_set_action;
1209 cb.set_commit = ${i}_set_commit;
1210 cb.set_free = ${i}_set_free;
1211 cb.set_undo = ${i}_set_undo;
1213 DEBUGMSGTL(("initialize_table_$i",
1214 "Registering table $i "
1215 "as a table array\n"));
1216 netsnmp_table_container_register(my_handler, table_info, &cb,
1220 /************************************************************
1224 netsnmp_request_info *request,
1225 netsnmp_index *item,
1226 netsnmp_table_request_info *table_info )
1228 netsnmp_variable_list *var = request->requestvb;
1229 ${i}_context *context = (${i}_context *)item;
1231 switch(table_info->colnum) {
1234 @eval $have_type = 0@
1236 /** $c.syntax = $c.type */
1237 @if "$c.type" eq "ASN_OBJECT_ID"@
1238 @eval $have_type = 1@
1239 snmp_set_var_typed_value(var, $c.type,
1240 (char*)&context->$c,
1241 context->${c}_len );
1243 @if "$c.type" eq "ASN_OCTET_STR"@
1244 @eval $have_type = 1@
1245 snmp_set_var_typed_value(var, $c.type,
1246 (char*)&context->$c,
1247 context->${c}_len );
1249 @if $have_type == 0@
1250 snmp_set_var_typed_value(var, $c.type,
1251 (char*)&context->$c,
1252 sizeof(context->$c) );
1257 default: /** We shouldn't get here */
1258 snmp_log(LOG_ERR, "unknown column in "
1259 "${i}_get_value\n");
1260 return SNMP_ERR_GENERR;
1262 return SNMP_ERR_NOERROR;
1265 /************************************************************
1268 const ${i}_context *
1269 ${i}_get_by_idx(netsnmp_index * hdr)
1271 return (const ${i}_context *)
1272 CONTAINER_FIND(cb.container, hdr );