mib2c.array-user.conf
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:37k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. ## -*- c -*-
  2. ##
  3. ## For documentation on the code generated by this configuration file,
  4. ## see the file agent/helpers/table_array.c.
  5. ##
  6. ######################################################################
  7. ## Do the .h file
  8. ## @perleval $vars{shortname} =~ s/([A-Z])[a-z]+/$1/g@
  9. ######################################################################
  10. @foreach $i table@
  11. @open ${i}.h@
  12. @eval $hack = "Id"
  13. /*
  14.  * Note: this file originally auto-generated by mib2c using
  15.  *        $Id: mib2c.array-user.conf,v 5.24.2.2 2005/04/26 22:13:28 rstory Exp $
  16.  *
  17.  * $$hack:$
  18.  *
  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!
  21.  */
  22. #ifndef $i.uc_H
  23. #define $i.uc_H
  24. #ifdef __cplusplus
  25. extern "C" {
  26. #endif
  27.     
  28. #include <net-snmp/net-snmp-config.h>
  29. #include <net-snmp/library/container.h>
  30. #include <net-snmp/agent/table_array.h>
  31.     @eval $ext_index = 0@
  32.     @foreach $idx index@
  33.         @if "$idx" ne ""@
  34.         @eval $found = "external"@
  35.         @foreach $c column@
  36.             @if "$idx" eq "$c"@
  37.                @eval $found = "internal"@
  38.             @end@
  39.         @end@
  40.         /** Index $idx is $found */
  41.         @if "$found" eq "external"@
  42.            @eval $ext_index = 1@
  43.         @end@
  44.         @end@
  45.     @end@
  46. typedef struct ${i}_context_s {
  47.     netsnmp_index index; /** THIS MUST BE FIRST!!! */
  48.     /*************************************************************
  49.      * You can store data internally in this structure.
  50.      *
  51.      * TODO: You will probably have to fix a few types here...
  52.      */
  53.     @if $ext_index != 0@
  54.     /** TODO: add storage for external index(s)! */
  55.     @end@
  56.     @foreach $c column@
  57.         /** $c.syntax = $c.type */
  58.         @eval $have_type = 0@
  59.         @if "$c.type" eq "ASN_OCTET_STR"@
  60.             @eval $have_type = 1@
  61.             @eval $o_len = "65535"@
  62.             @if "$c.syntax" eq "DisplayString"@
  63.                 @eval $o_len = "255"@
  64.             @end@
  65.             @if "$c.syntax" eq "SnmpAdminString"@
  66.                 @eval $o_len = "255"@
  67.             @end@
  68.             unsigned char $c[$o_len];
  69.             long ${c}_len;
  70.         @end@
  71.         @if "$c.type" eq "ASN_OBJECT_ID"@
  72.             @eval $have_type = 1@
  73.             oid $c[MAX_OID_LEN];
  74.             long ${c}_len;
  75.         @end@
  76.         @if "$c.type" eq "ASN_UNSIGNED"@
  77.             @eval $have_type = 1@
  78.             unsigned long $c;
  79.         @end@
  80.         @if "$c.type" eq "ASN_TIMETICKS"@
  81.             @eval $have_type = 1@
  82.             unsigned long $c;
  83.         @end@
  84.         @if "$c.type" eq "ASN_IPADDRESS"@
  85.             @eval $have_type = 1@
  86.             unsigned long $c;
  87.         @end@
  88.         @if "$c.type" eq "ASN_UINTEGER"@
  89.             @eval $have_type = 1@
  90.             unsigned long $c;
  91.         @end@
  92.         @if "$c.type" eq "ASN_INTEGER"@
  93.             @eval $have_type = 1@
  94.             long $c;
  95.         @end@
  96.         @if "$c.type" eq "ASN_COUNTER"@
  97.             @eval $have_type = 1@
  98.             unsigned long $c;
  99.         @end@
  100.         @if $have_type == 0@
  101.     /** TODO: Is this type correct? */
  102.             long $c;
  103.         @end@
  104.     @end@
  105.     /*
  106.      * OR
  107.      *
  108.      * Keep a pointer to your data
  109.      */
  110.     void * data;
  111.     /*
  112.      *add anything else you want here
  113.      */
  114. } ${i}_context;
  115. /*************************************************************
  116.  * function declarations
  117.  */
  118. void init_$i(void);
  119. void initialize_table_$i(void);
  120. const ${i}_context * ${i}_get_by_idx(netsnmp_index *);
  121. const ${i}_context * ${i}_get_by_idx_rs(netsnmp_index *,
  122.                                         int row_status);
  123. int ${i}_get_value(netsnmp_request_info *, netsnmp_index *, netsnmp_table_request_info *);
  124. /*************************************************************
  125.  * oid declarations
  126.  */
  127. extern oid ${i}_oid[];
  128. extern size_t ${i}_oid_len;
  129. #define ${i}_TABLE_OID $i.commaoid
  130.     
  131. /*************************************************************
  132.  * column number definitions for table $i
  133.  */
  134. @eval $minv = 0xffffffff@
  135. @eval $maxv = 0@
  136. @foreach $c column@
  137. #define COLUMN_$c.uc $c.subid
  138. @if ! $c.noaccess@
  139. @eval $minv = min($minv, $c.subid)@
  140. @eval $maxv = max($maxv, $c.subid)@
  141. @end@
  142. @if "$c.syntax" eq "RowStatus"@
  143.    @eval $rs_name = "$c"@
  144. @end@
  145. @if "$c.syntax" eq "StorageType"@
  146.    @eval $st_name = "$c"@
  147. @end@
  148. @end@
  149. #define ${i}_COL_MIN $minv
  150. #define ${i}_COL_MAX $maxv
  151. /* comment out the following line if you don't want a custom sort  */
  152. #define ${i}_CUSTOM_SORT
  153. @if "$rs_name" ne ""@
  154. /* uncommend the following line if you allow modifications to an
  155.  * active row */
  156. /** define ${i}_CAN_MODIFY_ACTIVE_ROW */
  157. @end@
  158. @if $i.settable@
  159. int ${i}_extract_index( ${i}_context * ctx, netsnmp_index * hdr );
  160. void ${i}_set_reserve1( netsnmp_request_group * );
  161. void ${i}_set_reserve2( netsnmp_request_group * );
  162. void ${i}_set_action( netsnmp_request_group * );
  163. void ${i}_set_commit( netsnmp_request_group * );
  164. void ${i}_set_free( netsnmp_request_group * );
  165. void ${i}_set_undo( netsnmp_request_group * );
  166. ${i}_context * ${i}_duplicate_row( ${i}_context* );
  167. netsnmp_index * ${i}_delete_row( ${i}_context* );
  168. @if "$rs_name" ne ""@
  169. int ${i}_can_activate(${i}_context *undo_ctx,
  170.                       ${i}_context *row_ctx,
  171.                       netsnmp_request_group * rg);
  172. int ${i}_can_deactivate(${i}_context *undo_ctx,
  173.                         ${i}_context *row_ctx,
  174.                         netsnmp_request_group * rg);
  175. @end@
  176. int ${i}_can_delete(${i}_context *undo_ctx,
  177.                     ${i}_context *row_ctx,
  178.                     netsnmp_request_group * rg);
  179.     
  180.     
  181. @if $i.creatable@
  182. ${i}_context * ${i}_create_row( netsnmp_index* );
  183. @end@
  184. @end@
  185. #ifdef ${i}_CUSTOM_SORT
  186. ${i}_context * ${i}_get( const char *name, int len );
  187. #endif
  188. #ifdef __cplusplus
  189. }
  190. #endif
  191. #endif /** $i.uc_H */
  192. @end@
  193. ######################################################################
  194. ## Do the .c file
  195. ######################################################################
  196. @foreach $i table@
  197. @open ${i}.c@
  198. @eval $hack = "Id"@
  199. /*
  200.  * Note: this file originally auto-generated by mib2c using
  201.  *       $Id: mib2c.array-user.conf,v 5.24.2.2 2005/04/26 22:13:28 rstory Exp $
  202.  *
  203.  * $$hack:$
  204.  *
  205.  *
  206.  * For help understanding NET-SNMP in general, please check the 
  207.  *     documentation and FAQ at:
  208.  *
  209.  *     http://www.net-snmp.org/
  210.  *
  211.  *
  212.  * For help understanding this code, the agent and how it processes
  213.  *     requests, please check the following references.
  214.  *
  215.  *     http://www.net-snmp.org/tutorial-5/
  216.  *
  217.  *
  218.  * You can also join the #net-snmp channel on irc.freenode.net
  219.  *     and ask for help there.
  220.  *
  221.  *
  222.  * And if all else fails, send a detailed message to the developers
  223.  *     describing the problem you are having to:
  224.  *
  225.  *    net-snmp-coders@lists.sourceforge.net
  226.  *
  227.  *
  228.  * Yes, there is lots of code here that you might not use. But it is much
  229.  * easier to remove code than to add it!
  230.  */
  231. #include <net-snmp/net-snmp-config.h>
  232. #include <net-snmp/net-snmp-includes.h>
  233. #include <net-snmp/agent/net-snmp-agent-includes.h>
  234. #include <net-snmp/library/snmp_assert.h>
  235. #include "${i}.h"
  236. static     netsnmp_handler_registration *my_handler = NULL;
  237. static     netsnmp_table_array_callbacks cb;
  238. oid ${i}_oid[] = { ${i}_TABLE_OID };
  239. size_t ${i}_oid_len = OID_LENGTH(${i}_oid);
  240. #ifdef ${i}_CUSTOM_SORT
  241. /************************************************************
  242.  * keep binary tree to find context by name
  243.  */
  244. static int ${i}_cmp( const void *lhs, const void *rhs );
  245. /************************************************************
  246.  * compare two context pointers here. Return -1 if lhs < rhs,
  247.  * 0 if lhs == rhs, and 1 if lhs > rhs.
  248.  */
  249. static int
  250. ${i}_cmp( const void *lhs, const void *rhs )
  251. {
  252.     ${i}_context *context_l =
  253.         (${i}_context *)lhs;
  254.     ${i}_context *context_r =
  255.         (${i}_context *)rhs;
  256.     /*
  257.      * check primary key, then secondary. Add your own code if
  258.      * there are more than 2 keys
  259.      */
  260.     int rc;
  261.     /*
  262.      * TODO: implement compare. Remove this ifdef code and
  263.      * add your own code here.
  264.      */
  265. #ifdef TABLE_CONTAINER_TODO
  266.     snmp_log(LOG_ERR,
  267.              "${i}_compare not implemented! Container order undefinedn" );
  268.     return 0;
  269. #endif
  270.     
  271.     /*
  272.      * EXAMPLE (assuming you want to sort on a name):
  273.      *   
  274.      * rc = strcmp( context_l->xxName, context_r->xxName );
  275.      *
  276.      * if(rc)
  277.      *   return rc;
  278.      *
  279.      * TODO: fix secondary keys (or delete if there are none)
  280.      *
  281.      * if(context_l->yy < context_r->yy) 
  282.      *   return -1;
  283.      *
  284.      * return (context_l->yy == context_r->yy) ? 0 : 1;
  285.      */
  286. }
  287. /************************************************************
  288.  * search tree
  289.  */
  290. /** TODO: set additional indexes as parameters */
  291. ${i}_context *
  292. ${i}_get( const char *name, int len )
  293. {
  294.     ${i}_context tmp;
  295.     /** we should have a custom container */
  296.     netsnmp_assert(cb.container->next != NULL);
  297.     
  298.     /*
  299.      * TODO: implement compare. Remove this ifdef code and
  300.      * add your own code here.
  301.      */
  302. #ifdef TABLE_CONTAINER_TODO
  303.     snmp_log(LOG_ERR, "${i}_get not implemented!n" );
  304.     return NULL;
  305. #endif
  306.     /*
  307.      * EXAMPLE:
  308.      *
  309.      * if(len > sizeof(tmp.xxName))
  310.      *   return NULL;
  311.      *
  312.      * strncpy( tmp.xxName, name, sizeof(tmp.xxName) );
  313.      * tmp.xxName_len = len;
  314.      *
  315.      * return CONTAINER_FIND(cb.container->next, &tmp);
  316.      */
  317. }
  318. #endif
  319. /************************************************************
  320.  * Initializes the $i module
  321.  */
  322. void
  323. init_$i(void)
  324. {
  325.     initialize_table_$i();
  326.     /*
  327.      * TODO: perform any startup stuff here, such as
  328.      * populating the table with initial data.
  329.      *
  330.      * ${i}_context * new_row = create_row(index);
  331.      * CONTAINER_INSERT(cb.container,new_row);
  332.      */
  333. }
  334. @if $i.settable@
  335. /************************************************************
  336.  * the *_row_copy routine
  337.  */
  338. static int ${i}_row_copy(${i}_context * dst,
  339.                          ${i}_context * src)
  340. {
  341.     if(!dst||!src)
  342.         return 1;
  343.         
  344.     /*
  345.      * copy index, if provided
  346.      */
  347.     if(dst->index.oids)
  348.         free(dst->index.oids);
  349.     if(snmp_clone_mem( (void*)&dst->index.oids, src->index.oids,
  350.                            src->index.len * sizeof(oid) )) {
  351.         dst->index.oids = NULL;
  352.         return 1;
  353.     }
  354.     dst->index.len = src->index.len;
  355.     
  356.     /*
  357.      * copy components into the context structure
  358.      */
  359.     @if $ext_index != 0@
  360.     /** TODO: add code for external index(s)! */
  361.     @end@
  362.     @foreach $c column@
  363.     @eval $have_type = 0@
  364.     @if "$c.type" eq "ASN_OCTET_STR"@
  365.     @eval $have_type = 1@
  366.     memcpy( dst->$c, src->$c, src->${c}_len );
  367.     dst->${c}_len = src->${c}_len;
  368.     @end@
  369.     @if "$c.type" eq "ASN_OBJECT_ID"@
  370.     @eval $have_type = 1@
  371.     memcpy( dst->$c, src->$c, src->${c}_len );
  372.     dst->${c}_len = src->${c}_len;
  373.     @end@
  374.     @if $have_type == 0@
  375.     dst->$c = src->$c;
  376.     @end@
  377.     @end@
  378.     return 0;
  379. }
  380. /**
  381.  * the *_extract_index routine
  382.  *
  383.  * This routine is called when a set request is received for an index
  384.  * that was not found in the table container. Here, we parse the oid
  385.  * in the the individual index components and copy those indexes to the
  386.  * context. Then we make sure the indexes for the new row are valid.
  387.  */
  388. int
  389. ${i}_extract_index( ${i}_context * ctx, netsnmp_index * hdr )
  390. {
  391.     /*
  392.      * temporary local storage for extracting oid index
  393.      *
  394.      * extract index uses varbinds (netsnmp_variable_list) to parse
  395.      * the index OID into the individual components for each index part.
  396.      */
  397.     @if $ext_index != 0@
  398.     /** TODO: add storage for external index(s)! */
  399.     @end@
  400.     @eval $first_idx = ""@
  401.     @foreach $idx index@
  402.         @if "$first_idx" eq ""@
  403.         @eval $first_idx = $idx@
  404.         @end@
  405.     netsnmp_variable_list var_$idx;
  406.     @end@
  407.     int err;
  408.     /*
  409.      * copy index, if provided
  410.      */
  411.     if(hdr) {
  412.         netsnmp_assert(ctx->index.oids == NULL);
  413.         if((hdr->len > MAX_OID_LEN) ||
  414.            snmp_clone_mem( (void*)&ctx->index.oids, hdr->oids,
  415.                            hdr->len * sizeof(oid) )) {
  416.             return -1;
  417.         }
  418.         ctx->index.len = hdr->len;
  419.     }
  420.     /*
  421.      * initialize variable that will hold each component of the index.
  422.      * If there are multiple indexes for the table, the variable_lists
  423.      * need to be linked together, in order.
  424.      */
  425.     @if $ext_index != 0@
  426.        /** TODO: add code for external index(s)! */
  427.     @end@
  428.     @foreach $idx index@
  429.        memset( &var_$idx, 0x00, sizeof(var_$idx) );
  430.        var_${idx}.type = $idx.type; /* type hint for parse_oid_indexes */
  431.        /** TODO: link this index to the next, or NULL for the last one */
  432. #ifdef TABLE_CONTAINER_TODO
  433.     snmp_log(LOG_ERR, "${i}_extract_index index list not implemented!n" );
  434.     return 0;
  435. #else
  436.        var_${idx}.next_variable = &var_XX;
  437. #endif
  438.     @end@
  439.     /*
  440.      * parse the oid into the individual index components
  441.      */
  442.     err = parse_oid_indexes( hdr->oids, hdr->len, &var_$first_idx );
  443.     if (err == SNMP_ERR_NOERROR) {
  444.        /*
  445.         * copy index components into the context structure
  446.         */
  447.        @foreach $idx index@
  448.           @eval $found = "external"@
  449.           @foreach $c column@
  450.               @if "$idx" eq "$c"@
  451.                  @eval $found = "internal"@
  452.               @end@
  453.           @end@
  454.           @if "$found" eq "external"@
  455.               /** skipping external index $idx */
  456.           @end@
  457.           @if "$found" eq "internal"@
  458.              @eval $have_type = 0@
  459.              @if "$idx.type" eq "ASN_OCTET_STR"@
  460.              @eval $have_type = 1@
  461.                 if(var_${idx}.val_len > sizeof(ctx->$idx))
  462.                    err = -1;
  463.                 else
  464.                     memcpy( ctx->$idx, var_${idx}.val.string, var_${idx}.val_len );
  465.                 ctx->${idx}_len = var_${idx}.val_len;
  466.              @end@
  467.              @if "$idx.type" eq "ASN_OBJECT_ID"@
  468.              @eval $have_type = 1@
  469.                 memcpy( ctx->$idx, var_${idx}.val.string, var_${idx}.val_len );
  470.                 ctx->${idx}_len = var_${idx}.val_len;
  471.              @end@
  472.              @if $have_type == 0@
  473.                 ctx->$idx = *var_${idx}.val.integer;
  474.              @end@
  475.           @end@
  476.    
  477.        @end@
  478.    
  479.        @foreach $c index@
  480.            /*
  481.             * TODO: check index for valid values. For EXAMPLE:
  482.             *
  483.           @eval $have_check = 0@
  484.           @if "$c.type" eq "ASN_IPADDRESS"@
  485.               @eval $have_check = 1@
  486.               * if ( XXX_check_ip( *var_${c}.val.integer ) ) {
  487.           @end@
  488.           @if "$c.type" eq "ASN_OBJECT_ID"@
  489.               @eval $have_check = 1@
  490.               * if ( XXX_check_oid( var_${c}.val.objid, var_${c}.val_len /
  491.                                     sizeof(oid) ) ) {
  492.           @end@
  493.           @if "$c.type" eq "ASN_OCTET_STR"@
  494.               @eval $have_check = 1@
  495.               * if ( XXX_check_value( var_${c}.val.string, XXX ) ) {
  496.           @end@
  497.           @if $have_check != 1@
  498.               * if ( *var_${c}.val.integer != XXX ) {
  499.           @end@
  500.           *    err = -1;
  501.           * }
  502.           */
  503.        @end@
  504.     }
  505.     /*
  506.      * parsing may have allocated memory. free it.
  507.      */
  508.     snmp_reset_var_buffers( &var_$first_idx );
  509.     return err;
  510. }
  511. @if "$rs_name" ne ""@
  512. /************************************************************
  513.  * the *_can_activate routine is called
  514.  * when a row is changed to determine if all the values
  515.  * set are consistent with the row's rules for a row status
  516.  * of ACTIVE.
  517.  *
  518.  * return 1 if the row could be ACTIVE
  519.  * return 0 if the row is not ready for the ACTIVE state
  520.  */
  521. int ${i}_can_activate(${i}_context *undo_ctx,
  522.                       ${i}_context *row_ctx,
  523.                       netsnmp_request_group * rg)
  524. {
  525.     /*
  526.      * TODO: check for activation requirements here
  527.      */
  528.     /*
  529.      * be optimistic.
  530.      */
  531.     return 1;
  532. }
  533. /************************************************************
  534.  * the *_can_deactivate routine is called when a row that is
  535.  * currently ACTIVE is set to a state other than ACTIVE. If
  536.  * there are conditions in which a row should not be allowed
  537.  * to transition out of the ACTIVE state (such as the row being
  538.  * referred to by another row or table), check for them here.
  539.  *
  540.  * return 1 if the row can be set to a non-ACTIVE state
  541.  * return 0 if the row must remain in the ACTIVE state
  542.  */
  543. int ${i}_can_deactivate(${i}_context *undo_ctx,
  544.                         ${i}_context *row_ctx,
  545.                         netsnmp_request_group * rg)
  546. {
  547.     /*
  548.      * TODO: check for deactivation requirements here
  549.      */
  550.     return 1;
  551. }
  552. @end@
  553. /************************************************************
  554.  * the *_can_delete routine is called to determine if a row
  555.  * can be deleted.
  556.  *
  557.  * return 1 if the row can be deleted
  558.  * return 0 if the row cannot be deleted
  559.  */
  560. int ${i}_can_delete(${i}_context *undo_ctx,
  561.                     ${i}_context *row_ctx,
  562.                     netsnmp_request_group * rg)
  563. {
  564. @if "$rs_name" ne ""@
  565.     /*
  566.      * probably shouldn't delete a row that we can't
  567.      * deactivate.
  568.      */
  569.     if(${i}_can_deactivate(undo_ctx,row_ctx,rg) != 1)
  570.         return 0;
  571. @end@
  572.     
  573.     /*
  574.      * TODO: check for other deletion requirements here
  575.      */
  576.     return 1;
  577. }
  578. @if $i.creatable@
  579. /************************************************************
  580.  * the *_create_row routine is called by the table handler
  581.  * to create a new row for a given index. If you need more
  582.  * information (such as column values) to make a decision
  583.  * on creating rows, you must create an initial row here
  584.  * (to hold the column values), and you can examine the
  585.  * situation in more detail in the *_set_reserve1 or later
  586.  * states of set processing. Simple check for a NULL undo_ctx
  587.  * in those states and do detailed creation checking there.
  588.  *
  589.  * returns a newly allocated ${i}_context
  590.  *   structure if the specified indexes are not illegal
  591.  * returns NULL for errors or illegal index values.
  592.  */
  593. ${i}_context *
  594. ${i}_create_row( netsnmp_index* hdr)
  595. {
  596.     ${i}_context * ctx =
  597.         SNMP_MALLOC_TYPEDEF(${i}_context);
  598.     if(!ctx)
  599.         return NULL;
  600.         
  601.     /*
  602.      * TODO: check indexes, if necessary.
  603.      */
  604.     if(${i}_extract_index( ctx, hdr )) {
  605.         if (NULL != ctx->index.oids)
  606.             free(ctx->index.oids);
  607.         free(ctx);
  608.         return NULL;
  609.     }
  610.     /* netsnmp_mutex_init(ctx->lock);
  611.        netsnmp_mutex_lock(ctx->lock); */
  612.     /*
  613.      * TODO: initialize any default values here. This is also
  614.      * first place you really should allocate any memory for
  615.      * yourself to use.  If you allocated memory earlier,
  616.      * make sure you free it for earlier error cases!
  617.      */
  618.     /**
  619.      @foreach $c column@
  620.      @if $c.settable@
  621.      ctx->$c = 0;
  622.      @end@
  623.      @end@
  624.     */
  625.     return ctx;
  626. }
  627. @end@
  628. /************************************************************
  629.  * the *_duplicate row routine
  630.  */
  631. ${i}_context *
  632. ${i}_duplicate_row( ${i}_context * row_ctx)
  633. {
  634.     ${i}_context * dup;
  635.     if(!row_ctx)
  636.         return NULL;
  637.     dup = SNMP_MALLOC_TYPEDEF(${i}_context);
  638.     if(!dup)
  639.         return NULL;
  640.         
  641.     if(${i}_row_copy(dup,row_ctx)) {
  642.         free(dup);
  643.         dup = NULL;
  644.     }
  645.     return dup;
  646. }
  647. /************************************************************
  648.  * the *_delete_row method is called to delete a row.
  649.  */
  650. netsnmp_index * ${i}_delete_row( ${i}_context * ctx )
  651. {
  652.   /* netsnmp_mutex_destroy(ctx->lock); */
  653.     if(ctx->index.oids)
  654.         free(ctx->index.oids);
  655.     /*
  656.      * TODO: release any memory you allocated here...
  657.      */
  658.     /*
  659.      * release header
  660.      */
  661.     free( ctx );
  662.     return NULL;
  663. }
  664. /************************************************************
  665.  * RESERVE is used to check the syntax of all the variables
  666.  * provided, that the values being set are sensible and consistent,
  667.  * and to allocate any resources required for performing the SET.
  668.  * After this stage, the expectation is that the set ought to
  669.  * succeed, though this is not guaranteed. (In fact, with the UCD
  670.  * agent, this is done in two passes - RESERVE1, and
  671.  * RESERVE2, to allow for dependancies between variables).
  672.  *
  673.  * BEFORE calling this routine, the agent will call duplicate_row
  674.  * to create a copy of the row (unless this is a new row; i.e.
  675.  * row_created == 1).
  676.  *
  677.  * next state -> SET_RESERVE2 || SET_FREE
  678.  */
  679. void ${i}_set_reserve1( netsnmp_request_group *rg )
  680. {
  681.     ${i}_context *row_ctx =
  682.             (${i}_context *)rg->existing_row;
  683.     ${i}_context *undo_ctx =
  684.             (${i}_context *)rg->undo_info;
  685.     netsnmp_variable_list *var;
  686.     netsnmp_request_group_item *current;
  687.     int rc;
  688.     @if "$st_name" ne ""@
  689.         /*
  690.          * Block all attempts to modify a readOnly row
  691.          */
  692.     if( row_ctx && (row_ctx->$st_name == SNMP_STORAGE_READONLY) ) {
  693.         netsnmp_set_mode_request_error(MODE_SET_BEGIN, rg->list->ri,
  694.                                        SNMP_ERR_NOTWRITABLE);
  695.         return;
  696.     }
  697.     @end@
  698.     /*
  699.      * TODO: loop through columns, check syntax and lengths. For
  700.      * columns which have no dependencies, you could also move
  701.      * the value/range checking here to attempt to catch error
  702.      * cases as early as possible.
  703.      */
  704.     for( current = rg->list; current; current = current->next ) {
  705.         var = current->ri->requestvb;
  706.         rc = SNMP_ERR_NOERROR;
  707.         switch(current->tri->colnum) {
  708.         @foreach $c column@
  709.         @if $c.settable@
  710.         case COLUMN_$c.uc:
  711.             /** $c.syntax = $c.type */
  712.             rc = netsnmp_check_vb_type_and_size(var, $c.type,
  713.                                                 sizeof(row_ctx->$c));
  714.         break;
  715.         @end@
  716.         @end@
  717.         default: /** We shouldn't get here */
  718.             rc = SNMP_ERR_GENERR;
  719.             snmp_log(LOG_ERR, "unknown column in "
  720.                      "${i}_set_reserve1n");
  721.         }
  722.         if (rc)
  723.            netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc );
  724.         rg->status = SNMP_MAX( rg->status, current->ri->status );
  725.     }
  726.     /*
  727.      * done with all the columns. Could check row related
  728.      * requirements here.
  729.      */
  730. }
  731. void ${i}_set_reserve2( netsnmp_request_group *rg )
  732. {
  733.     ${i}_context *row_ctx = (${i}_context *)rg->existing_row;
  734.     ${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
  735.     netsnmp_request_group_item *current;
  736.     netsnmp_variable_list *var;
  737.     int rc;
  738.     rg->rg_void = rg->list->ri;
  739.     /*
  740.      * TODO: loop through columns, check for valid
  741.      * values and any range constraints.
  742.      */
  743.     for( current = rg->list; current; current = current->next ) {
  744.         var = current->ri->requestvb;
  745.         rc = SNMP_ERR_NOERROR;
  746.         switch(current->tri->colnum) {
  747.         @foreach $c column@
  748.         @if $c.settable@
  749.         case COLUMN_$c.uc:
  750.             /** $c.syntax = $c.type */
  751.             @eval $have_check = 0@
  752.             @if "$c" eq "$st_name"@
  753.                 @eval $have_check = 1@
  754.                 rc = netsnmp_check_vb_storagetype(current->ri->requestvb,
  755.                                                   undo_ctx ?
  756.                                                   undo_ctx->$c:0);
  757.             @end@
  758.             @if "$c" eq "$rs_name"@
  759.                 @eval $have_check = 1@
  760.                 rc = netsnmp_check_vb_rowstatus(current->ri->requestvb,
  761.                                                 undo_ctx ?
  762.                                                 undo_ctx->$c:0);
  763.                 rg->rg_void = current->ri;
  764.             @end@
  765.             @if "$c.syntax" eq "TruthValue"@
  766.                 @eval $have_check = 1@
  767.                 rc = netsnmp_check_vb_truthvalue(current->ri->requestvb);
  768.             @end@
  769.             @if $have_check == 0@
  770.                     /*
  771.                      * TODO: routine to check valid values
  772.                      *
  773.                      * EXAMPLE:
  774.                      *
  775.                 @if "$c.type" eq "ASN_IPADDRESS"@
  776.                     @eval $have_check = 1@
  777.                     * if ( XXX_check_ip( *var->val.integer ) ) {
  778.                 @end@
  779.                 @if "$c.type" eq "ASN_OBJECT_ID"@
  780.                     @eval $have_check = 1@
  781.                     * if ( XXX_check_oid( var ) ) {
  782.                 @end@
  783.                 @if "$c.type" eq "ASN_OCTET_STR"@
  784.                     @eval $have_check = 1@
  785.                     * if ( XXX_check_value( var->val.string, XXX ) ) {
  786.                 @end@
  787.                 @if $have_check != 1@
  788.                     * if ( *var->val.integer != XXX ) {
  789.                 @end@
  790.                 *    rc = SNMP_ERR_INCONSISTENTVALUE;
  791.                 *    rc = SNMP_ERR_BADVALUE;
  792.                 * }
  793.                 */
  794.             @end@
  795.         break;
  796.         @end@
  797.         @end@
  798.         default: /** We shouldn't get here */
  799.             netsnmp_assert(0); /** why wasn't this caught in reserve1? */
  800.         }
  801.         if (rc)
  802.            netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc);
  803.     }
  804.     /*
  805.      * done with all the columns. Could check row related
  806.      * requirements here.
  807.      */
  808. }
  809. /************************************************************
  810.  * Assuming that the RESERVE phases were successful, the next
  811.  * stage is indicated by the action value ACTION. This is used
  812.  * to actually implement the set operation. However, this must
  813.  * either be done into temporary (persistent) storage, or the
  814.  * previous value stored similarly, in case any of the subsequent
  815.  * ACTION calls fail.
  816.  *
  817.  * In your case, changes should be made to row_ctx. A copy of
  818.  * the original row is in undo_ctx.
  819.  */
  820. void ${i}_set_action( netsnmp_request_group *rg )
  821. {
  822.     netsnmp_variable_list *var;
  823.     ${i}_context *row_ctx = (${i}_context *)rg->existing_row;
  824.     ${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
  825.     netsnmp_request_group_item *current;
  826.     @if "$rs_name" ne ""@
  827.     int            row_err = 0;
  828.     @end@
  829.     /*
  830.      * TODO: loop through columns, copy varbind values
  831.      * to context structure for the row.
  832.      */
  833.     for( current = rg->list; current; current = current->next ) {
  834.         var = current->ri->requestvb;
  835.         switch(current->tri->colnum) {
  836.         @foreach $c column@
  837.         @if $c.settable@
  838.         case COLUMN_$c.uc:
  839.             /** $c.syntax = $c.type */
  840.             @eval $have_type = 0@
  841.             @if "$c.type" eq "ASN_OCTET_STR"@
  842.             @eval $have_type = 1@
  843.             memcpy(row_ctx->$c,var->val.string,var->val_len);
  844.             row_ctx->${c}_len = var->val_len;
  845.             @end@
  846.             @if "$c.type" eq "ASN_OBJECT_ID"@
  847.             @eval $have_type = 1@
  848.             memcpy(row_ctx->$c,var->val.objid,var->val_len);
  849.             row_ctx->${c}_len = var->val_len;
  850.             @end@
  851.             @if $have_type == 0@
  852.             row_ctx->$c = *var->val.integer;
  853.             @end@
  854.         break;
  855.         @end@
  856.         @end@
  857.         default: /** We shouldn't get here */
  858.             netsnmp_assert(0); /** why wasn't this caught in reserve1? */
  859.         }
  860.     }
  861.     /*
  862.      * done with all the columns. Could check row related
  863.      * requirements here.
  864.      */
  865.     @if "$rs_name" ne ""@
  866. #ifndef ${i}_CAN_MODIFY_ACTIVE_ROW
  867.     if( undo_ctx && RS_IS_ACTIVE(undo_ctx->$rs_name) &&
  868.         row_ctx && RS_IS_ACTIVE(row_ctx->$rs_name) ) {
  869.             row_err = 1;
  870.     }
  871. #endif
  872.     /*
  873.      * check activation/deactivation
  874.      */
  875.     row_err = netsnmp_table_array_check_row_status(&cb, rg,
  876.                                   row_ctx ? &row_ctx->$rs_name : NULL,
  877.                                   undo_ctx ? &undo_ctx->$rs_name : NULL);
  878.     if(row_err) {
  879.         netsnmp_set_mode_request_error(MODE_SET_BEGIN,
  880.                                        (netsnmp_request_info*)rg->rg_void,
  881.                                        row_err);
  882.         return;
  883.     }
  884.     @end@
  885.     /*
  886.      * TODO: if you have dependencies on other tables, this would be
  887.      * a good place to check those, too.
  888.      */
  889. }
  890. /************************************************************
  891.  * Only once the ACTION phase has completed successfully, can
  892.  * the final COMMIT phase be run. This is used to complete any
  893.  * writes that were done into temporary storage, and then release
  894.  * any allocated resources. Note that all the code in this phase
  895.  * should be "safe" code that cannot possibly fail (cue
  896.  * hysterical laughter). The whole intent of the ACTION/COMMIT
  897.  * division is that all of the fallible code should be done in
  898.  * the ACTION phase, so that it can be backed out if necessary.
  899.  *
  900.  * BEFORE calling this routine, the agent will update the
  901.  * container (inserting a row if row_created == 1, or removing
  902.  * the row if row_deleted == 1).
  903.  *
  904.  * AFTER calling this routine, the agent will delete the
  905.  * undo_info.
  906.  */
  907. void ${i}_set_commit( netsnmp_request_group *rg )
  908. {
  909.     netsnmp_variable_list *var;
  910.     ${i}_context *row_ctx = (${i}_context *)rg->existing_row;
  911.     ${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
  912.     netsnmp_request_group_item *current;
  913.     /*
  914.      * loop through columns
  915.      */
  916.     for( current = rg->list; current; current = current->next ) {
  917.         var = current->ri->requestvb;
  918.         switch(current->tri->colnum) {
  919.         @foreach $c column@
  920.         @if $c.settable@
  921.         case COLUMN_$c.uc:
  922.             /** $c.syntax = $c.type */
  923.         break;
  924.         @end@
  925.         @end@
  926.         default: /** We shouldn't get here */
  927.             netsnmp_assert(0); /** why wasn't this caught in reserve1? */
  928.         }
  929.     }
  930.     /*
  931.      * done with all the columns. Could check row related
  932.      * requirements here.
  933.      */
  934. }
  935. /************************************************************
  936.  * If either of the RESERVE calls fail, the write routines
  937.  * are called again with the FREE action, to release any resources
  938.  * that have been allocated. The agent will then return a failure
  939.  * response to the requesting application.
  940.  *
  941.  * AFTER calling this routine, the agent will delete undo_info.
  942.  */
  943. void ${i}_set_free( netsnmp_request_group *rg )
  944. {
  945.     netsnmp_variable_list *var;
  946.     ${i}_context *row_ctx = (${i}_context *)rg->existing_row;
  947.     ${i}_context *undo_ctx = (${i}_context *)rg->undo_info;
  948.     netsnmp_request_group_item *current;
  949.     /*
  950.      * loop through columns
  951.      */
  952.     for( current = rg->list; current; current = current->next ) {
  953.         var = current->ri->requestvb;
  954.         switch(current->tri->colnum) {
  955.         @foreach $c column@
  956.         @if $c.settable@
  957.         case COLUMN_$c.uc:
  958.             /** $c.syntax = $c.type */
  959.         break;
  960.         @end@
  961.         @end@
  962.         default: /** We shouldn't get here */
  963.             /** should have been logged in reserve1 */
  964.         }
  965.     }
  966.     /*
  967.      * done with all the columns. Could check row related
  968.      * requirements here.
  969.      */
  970. }
  971. /************************************************************
  972.  * If the ACTION phase does fail (for example due to an apparently
  973.  * valid, but unacceptable value, or an unforeseen problem), then
  974.  * the list of write routines are called again, with the UNDO
  975.  * action. This requires the routine to reset the value that was
  976.  * changed to its previous value (assuming it was actually changed),
  977.  * and then to release any resources that had been allocated. As
  978.  * with the FREE phase, the agent will then return an indication
  979.  * of the error to the requesting application.
  980.  *
  981.  * BEFORE calling this routine, the agent will update the container
  982.  * (remove any newly inserted row, re-insert any removed row).
  983.  *
  984.  * AFTER calling this routing, the agent will call row_copy
  985.  * to restore the data in existing_row from the date in undo_info.
  986.  * Then undo_info will be deleted (or existing row, if row_created
  987.  * == 1).
  988.  */
  989. void ${i}_set_undo( netsnmp_request_group *rg )
  990. {
  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;
  995.     /*
  996.      * loop through columns
  997.      */
  998.     for( current = rg->list; current; current = current->next ) {
  999.         var = current->ri->requestvb;
  1000.         switch(current->tri->colnum) {
  1001.         @foreach $c column@
  1002.         @if $c.settable@
  1003.         case COLUMN_$c.uc:
  1004.             /** $c.syntax = $c.type */
  1005.         break;
  1006.         @end@
  1007.         @end@
  1008.         default: /** We shouldn't get here */
  1009.             netsnmp_assert(0); /** why wasn't this caught in reserve1? */
  1010.         }
  1011.     }
  1012.     /*
  1013.      * done with all the columns. Could check row related
  1014.      * requirements here.
  1015.      */
  1016. }
  1017. @end@
  1018. /************************************************************
  1019.  *
  1020.  * Initialize the $i table by defining its contents and how it's structured
  1021.  */
  1022. void
  1023. initialize_table_$i(void)
  1024. {
  1025.     netsnmp_table_registration_info *table_info;
  1026.     if(my_handler) {
  1027.         snmp_log(LOG_ERR, "initialize_table_${i}_handler called againn");
  1028.         return;
  1029.     }
  1030.     memset(&cb, 0x00, sizeof(cb));
  1031.     /** create the table structure itself */
  1032.     table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
  1033.     my_handler = netsnmp_create_handler_registration("$i",
  1034.                                              netsnmp_table_array_helper_handler,
  1035.                                              ${i}_oid,
  1036.                                              ${i}_oid_len,
  1037. @if $i.settable@
  1038.                                              HANDLER_CAN_RWRITE
  1039. @else@
  1040.                                              HANDLER_CAN_RONLY
  1041. @end@
  1042.                                              );
  1043.             
  1044.     if (!my_handler || !table_info) {
  1045.         snmp_log(LOG_ERR, "malloc failed in "
  1046.                  "initialize_table_${i}_handlern");
  1047.         return; /** mallocs failed */
  1048.     }
  1049.     /***************************************************
  1050.      * Setting up the table's definition
  1051.      */
  1052.     /*
  1053.      * TODO: add any external indexes here.
  1054.      */
  1055.     @if $ext_index != 0@
  1056.         /** TODO: add code for external index(s)! */
  1057.     @end@
  1058.     /*
  1059.      * internal indexes
  1060.      */
  1061.     @foreach $idx index@
  1062.         /** index: $idx */
  1063.         netsnmp_table_helper_add_index(table_info, $idx.type);
  1064.     @end@
  1065.     table_info->min_column = ${i}_COL_MIN;
  1066.     table_info->max_column = ${i}_COL_MAX;
  1067.     /***************************************************
  1068.      * registering the table with the master agent
  1069.      */
  1070.     cb.get_value = ${i}_get_value;
  1071.     cb.container = netsnmp_container_find("${i}_primary:"
  1072.                                           "${i}:"
  1073.                                           "table_container");
  1074. #ifdef ${i}_CUSTOM_SORT
  1075.     netsnmp_container_add_index(cb.container,
  1076.                                 netsnmp_container_find("${i}_custom:"
  1077.                                                        "${i}:"
  1078.                                                        "table_container"));
  1079.     cb.container->next->compare = ${i}_cmp;
  1080. #endif
  1081. @if $i.settable@
  1082.     cb.can_set = 1;
  1083. @if $i.creatable@
  1084.     cb.create_row = (UserRowMethod*)${i}_create_row;
  1085. @end@
  1086.     cb.duplicate_row = (UserRowMethod*)${i}_duplicate_row;
  1087.     cb.delete_row = (UserRowMethod*)${i}_delete_row;
  1088.     cb.row_copy = (Netsnmp_User_Row_Operation *)${i}_row_copy;
  1089. @if "$rs_name" ne ""@
  1090.     cb.can_activate = (Netsnmp_User_Row_Action *)${i}_can_activate;
  1091.     cb.can_deactivate = (Netsnmp_User_Row_Action *)${i}_can_deactivate;
  1092. @end@
  1093.     cb.can_delete = (Netsnmp_User_Row_Action *)${i}_can_delete;
  1094.     cb.set_reserve1 = ${i}_set_reserve1;
  1095.     cb.set_reserve2 = ${i}_set_reserve2;
  1096.     cb.set_action = ${i}_set_action;
  1097.     cb.set_commit = ${i}_set_commit;
  1098.     cb.set_free = ${i}_set_free;
  1099.     cb.set_undo = ${i}_set_undo;
  1100. @end@
  1101.     DEBUGMSGTL(("initialize_table_$i",
  1102.                 "Registering table $i "
  1103.                 "as a table arrayn"));
  1104.     netsnmp_table_container_register(my_handler, table_info, &cb,
  1105.                                      cb.container, 1);
  1106. }
  1107. /************************************************************
  1108.  * ${i}_get_value
  1109.  *
  1110.  * This routine is called for get requests to copy the data
  1111.  * from the context to the varbind for the request. If the
  1112.  * context has been properly maintained, you don't need to
  1113.  * change in code in this fuction.
  1114.  */
  1115. int ${i}_get_value(
  1116.             netsnmp_request_info *request,
  1117.             netsnmp_index *item,
  1118.             netsnmp_table_request_info *table_info )
  1119. {
  1120.     netsnmp_variable_list *var = request->requestvb;
  1121.     ${i}_context *context = (${i}_context *)item;
  1122.     switch(table_info->colnum) {
  1123.         @foreach $c column@
  1124.         @if $c.readable@
  1125.             @eval $have_type = 0@
  1126.         case COLUMN_$c.uc:
  1127.             /** $c.syntax = $c.type */
  1128.             @if "$c.type" eq "ASN_OBJECT_ID"@
  1129.                 @eval $have_type = 1@
  1130.             snmp_set_var_typed_value(var, $c.type,
  1131.                          (char*)&context->$c,
  1132.                          context->${c}_len );
  1133.             @end@
  1134.             @if "$c.type" eq "ASN_OCTET_STR"@
  1135.                 @eval $have_type = 1@
  1136.             snmp_set_var_typed_value(var, $c.type,
  1137.                          (char*)&context->$c,
  1138.                          context->${c}_len );
  1139.             @end@
  1140.             @if $have_type == 0@
  1141.             snmp_set_var_typed_value(var, $c.type,
  1142.                          (char*)&context->$c,
  1143.                          sizeof(context->$c) );
  1144.             @end@
  1145.         break;
  1146.     
  1147.         @end@
  1148.         @end@
  1149.     default: /** We shouldn't get here */
  1150.         snmp_log(LOG_ERR, "unknown column in "
  1151.                  "${i}_get_valuen");
  1152.         return SNMP_ERR_GENERR;
  1153.     }
  1154.     return SNMP_ERR_NOERROR;
  1155. }
  1156. /************************************************************
  1157.  * ${i}_get_by_idx
  1158.  */
  1159. const ${i}_context *
  1160. ${i}_get_by_idx(netsnmp_index * hdr)
  1161. {
  1162.     return (const ${i}_context *)
  1163.         CONTAINER_FIND(cb.container, hdr );
  1164. }
  1165. @end@