table_array.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:30k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * table_array.c
  3.  * $Id: table_array.c,v 5.23.2.1 2004/12/10 03:39:39 rstory Exp $
  4.  */
  5. #include <net-snmp/net-snmp-config.h>
  6. #if HAVE_STRING_H
  7. #include <string.h>
  8. #else
  9. #include <strings.h>
  10. #endif
  11. #include <net-snmp/net-snmp-includes.h>
  12. #include <net-snmp/agent/net-snmp-agent-includes.h>
  13. #include <net-snmp/agent/table.h>
  14. #include <net-snmp/agent/table_array.h>
  15. #include <net-snmp/library/container.h>
  16. #include <net-snmp/library/snmp_assert.h>
  17. #if HAVE_DMALLOC_H
  18. #include <dmalloc.h>
  19. #endif
  20. /*
  21.  * snmp.h:#define SNMP_MSG_INTERNAL_SET_BEGIN        -1 
  22.  * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE1     0 
  23.  * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE2     1 
  24.  * snmp.h:#define SNMP_MSG_INTERNAL_SET_ACTION       2 
  25.  * snmp.h:#define SNMP_MSG_INTERNAL_SET_COMMIT       3 
  26.  * snmp.h:#define SNMP_MSG_INTERNAL_SET_FREE         4 
  27.  * snmp.h:#define SNMP_MSG_INTERNAL_SET_UNDO         5 
  28.  */
  29. static const char *mode_name[] = {
  30.     "Reserve 1",
  31.     "Reserve 2",
  32.     "Action",
  33.     "Commit",
  34.     "Free",
  35.     "Undo"
  36. };
  37. /*
  38.  * PRIVATE structure for holding important info for each table.
  39.  */
  40. typedef struct table_container_data_s {
  41.    /** registration info for the table */
  42.     netsnmp_table_registration_info *tblreg_info;
  43.    /** container for the table rows */
  44.    netsnmp_container          *table;
  45.     /*
  46.      * mutex_type                lock;
  47.      */
  48.    /** do we want to group rows with the same index
  49.     * together when calling callbacks? */
  50.     int             group_rows;
  51.    /** callbacks for this table */
  52.     netsnmp_table_array_callbacks *cb;
  53. } table_container_data;
  54. /** @defgroup table_array table_array: Helps you implement a table when data can be stored locally. The data is stored in a sorted array, using a binary search for lookups.
  55.  *  @ingroup table
  56.  *
  57.  *  The table_array handler is used (automatically) in conjuntion
  58.  *  with the @link table table@endlink handler. It is primarily
  59.  *  intended to be used with the mib2c configuration file
  60.  *  mib2c.array-user.conf.
  61.  *
  62.  *  The code generated by mib2c is useful when you have control of
  63.  *  the data for each row. If you cannot control when rows are added
  64.  *  and deleted (or at least be notified of changes to row data),
  65.  *  then this handler is probably not for you.
  66.  *
  67.  *  This handler makes use of callbacks (function pointers) to
  68.  *  handle various tasks. Code is generated for each callback,
  69.  *  but will need to be reviewed and flushed out by the user.
  70.  *
  71.  *  NOTE NOTE NOTE: Once place where mib2c is somewhat lacking
  72.  *  is with regards to tables with external indices. If your
  73.  *  table makes use of one or more external indices, please
  74.  *  review the generated code very carefully for comments
  75.  *  regarding external indices.
  76.  *
  77.  *  NOTE NOTE NOTE: This helper, the API and callbacks are still
  78.  *  being tested and may change.
  79.  *
  80.  *  The generated code will define a structure for storage of table
  81.  *  related data. This structure must be used, as it contains the index
  82.  *  OID for the row, which is used for keeping the array sorted. You can
  83.  *  add addition fields or data to the structure for your own use.
  84.  *
  85.  *  The generated code will also have code to handle SNMP-SET processing.
  86.  *  If your table does not support any SET operations, simply comment
  87.  *  out the #define <PREFIX>_SET_HANDLING (where <PREFIX> is your
  88.  *  table name) in the header file.
  89.  *
  90.  *  SET processing modifies the row in-place. The duplicate_row
  91.  *  callback will be called to save a copy of the original row.
  92.  *  In the event of a failure before the commite phase, the
  93.  *  row_copy callback will be called to restore the original row
  94.  *  from the copy.
  95.  *
  96.  *  Code will be generated to handle row creation. This code may be
  97.  *  disabled by commenting out the #define <PREFIX>_ROW_CREATION
  98.  *  in the header file.
  99.  *
  100.  *  If your table contains a RowStatus object, by default the
  101.  *  code will not allow object in an active row to be modified.
  102.  *  To allow active rows to be modified, remove the comment block
  103.  *  around the #define <PREFIX>_CAN_MODIFY_ACTIVE_ROW in the header
  104.  *  file.
  105.  *
  106.  *  Code will be generated to maintain a secondary index for all
  107.  *  rows, stored in a binary tree. This is very useful for finding
  108.  *  rows by a key other than the OID index. By default, the functions
  109.  *  for maintaining this tree will be based on a character string.
  110.  *  NOTE: this will likely be made into a more generic mechanism,
  111.  *  using new callback methods, in the near future.
  112.  *
  113.  *  The generated code contains many TODO comments. Make sure you
  114.  *  check each one to see if it applies to your code. Examples include
  115.  *  checking indices for syntax (ranges, etc), initializing default
  116.  *  values in newly created rows, checking for row activation and
  117.  *  deactivation requirements, etc.
  118.  *
  119.  * @{
  120.  */
  121. /**********************************************************************
  122.  **********************************************************************
  123.  *                                                                    *
  124.  *                                                                    *
  125.  * PUBLIC Registration functions                                      *
  126.  *                                                                    *
  127.  *                                                                    *
  128.  **********************************************************************
  129.  **********************************************************************/
  130. /** register specified callbacks for the specified table/oid. If the
  131.     group_rows parameter is set, the row related callbacks will be
  132.     called once for each unique row index. Otherwise, each callback
  133.     will be called only once, for all objects.
  134. */
  135. int
  136. netsnmp_table_container_register(netsnmp_handler_registration *reginfo,
  137.                              netsnmp_table_registration_info *tabreg,
  138.                              netsnmp_table_array_callbacks *cb,
  139.                              netsnmp_container *container,
  140.                              int group_rows)
  141. {
  142.     table_container_data *tad = SNMP_MALLOC_TYPEDEF(table_container_data);
  143.     if (!tad)
  144.         return SNMPERR_GENERR;
  145.     tad->tblreg_info = tabreg;  /* we need it too, but it really is not ours */
  146.     if (!cb) {
  147.         snmp_log(LOG_ERR, "table_array registration with no callbacksn" );
  148.         return SNMPERR_GENERR;
  149.     }
  150.     /*
  151.      * check for required callbacks
  152.      */
  153.     if ((cb->can_set &&
  154.          ((NULL==cb->duplicate_row) || (NULL==cb->delete_row) ||
  155.           (NULL==cb->row_copy)) )) {
  156.         snmp_log(LOG_ERR, "table_array registration with incomplete "
  157.                  "callback structure.n");
  158.         return SNMPERR_GENERR;
  159.     }
  160.     if (NULL==container)
  161.         tad->table = netsnmp_container_find("table_array");
  162.     else
  163.         tad->table = container;
  164.     if (NULL==container->compare)
  165.         container->compare = netsnmp_compare_netsnmp_index;
  166.     if (NULL==container->ncompare)
  167.         container->ncompare = netsnmp_ncompare_netsnmp_index;
  168.     
  169.     tad->cb = cb;
  170.     reginfo->handler->myvoid = tad;
  171.     return netsnmp_register_table(reginfo, tabreg);
  172. }
  173. /** find the handler for the table_array helper. */
  174. netsnmp_mib_handler *
  175. netsnmp_find_table_array_handler(netsnmp_handler_registration *reginfo)
  176. {
  177.     netsnmp_mib_handler *mh;
  178.     if (!reginfo)
  179.         return NULL;
  180.     mh = reginfo->handler;
  181.     while (mh) {
  182.         if (mh->access_method == netsnmp_table_array_helper_handler)
  183.             break;
  184.         mh = mh->next;
  185.     }
  186.     return mh;
  187. }
  188. /** find the context data used by the table_array helper */
  189. netsnmp_container      *
  190. netsnmp_extract_array_context(netsnmp_request_info *request)
  191. {
  192.     return netsnmp_request_get_list_data(request, TABLE_ARRAY_NAME);
  193. }
  194. /** this function is called to validate RowStatus transitions. */
  195. int
  196. netsnmp_table_array_check_row_status(netsnmp_table_array_callbacks *cb,
  197.                                      netsnmp_request_group *ag,
  198.                                      long *rs_new, long *rs_old)
  199. {
  200.     netsnmp_index *row_ctx;
  201.     netsnmp_index *undo_ctx;
  202.     if (!ag || !cb)
  203.         return SNMPERR_GENERR;
  204.     row_ctx  = ag->existing_row;
  205.     undo_ctx = ag->undo_info;
  206.     
  207.     /*
  208.      * xxx-rks: revisit row delete scenario
  209.      */
  210.     if (row_ctx) {
  211.         /*
  212.          * either a new row, or change to old row
  213.          */
  214.         /*
  215.          * is it set to active?
  216.          */
  217.         if (RS_IS_GOING_ACTIVE(*rs_new)) {
  218.             /*
  219.              * is it ready to be active?
  220.              */
  221.             if ((NULL==cb->can_activate) ||
  222.                 cb->can_activate(undo_ctx, row_ctx, ag))
  223.                 *rs_new = RS_ACTIVE;
  224.             else
  225.                 return SNMP_ERR_INCONSISTENTVALUE;
  226.         } else {
  227.             /*
  228.              * not going active
  229.              */
  230.             if (undo_ctx) {
  231.                 /*
  232.                  * change
  233.                  */
  234.                 if (RS_IS_ACTIVE(*rs_old)) {
  235.                     /*
  236.                      * check pre-reqs for deactivation
  237.                      */
  238.                     if (cb->can_deactivate &&
  239.                         !cb->can_deactivate(undo_ctx, row_ctx, ag)) {
  240.                         return SNMP_ERR_INCONSISTENTVALUE;
  241.                     }
  242.                 }
  243.             } else {
  244.                 /*
  245.                  * new row
  246.                  */
  247.             }
  248.             if (*rs_new != RS_DESTROY) {
  249.                 if ((NULL==cb->can_activate) ||
  250.                     cb->can_activate(undo_ctx, row_ctx, ag))
  251.                     *rs_new = RS_NOTINSERVICE;
  252.                 else
  253.                     *rs_new = RS_NOTREADY;
  254.             } else {
  255.                 if (cb->can_delete && !cb->can_delete(undo_ctx, row_ctx, ag)) {
  256.                     return SNMP_ERR_INCONSISTENTVALUE;
  257.                 }
  258.                 ag->row_deleted = 1;
  259.             }
  260.         }
  261.     } else {
  262.         /*
  263.          * check pre-reqs for delete row
  264.          */
  265.         if (cb->can_delete && !cb->can_delete(undo_ctx, row_ctx, ag)) {
  266.             return SNMP_ERR_INCONSISTENTVALUE;
  267.         }
  268.     }
  269.     return SNMP_ERR_NOERROR;
  270. }
  271. /** @} */
  272. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  273. /**********************************************************************
  274.  **********************************************************************
  275.  **********************************************************************
  276.  **********************************************************************
  277.  *                                                                    *
  278.  *                                                                    *
  279.  *                                                                    *
  280.  *                                                                    *
  281.  * EVERYTHING BELOW THIS IS PRIVATE IMPLEMENTATION DETAILS.           *
  282.  *                                                                    *
  283.  *                                                                    *
  284.  *                                                                    *
  285.  *                                                                    *
  286.  **********************************************************************
  287.  **********************************************************************
  288.  **********************************************************************
  289.  **********************************************************************/
  290. /**********************************************************************
  291.  **********************************************************************
  292.  *                                                                    *
  293.  *                                                                    *
  294.  * Structures, Utility/convenience functions                          *
  295.  *                                                                    *
  296.  *                                                                    *
  297.  **********************************************************************
  298.  **********************************************************************/
  299. /*
  300.  * context info for SET requests
  301.  */
  302. typedef struct set_context_s {
  303.     netsnmp_agent_request_info *agtreq_info;
  304.     table_container_data *tad;
  305.     int             status;
  306. } set_context;
  307. static void
  308. release_netsnmp_request_group(netsnmp_index *g, void *v)
  309. {
  310.     netsnmp_request_group_item *tmp;
  311.     netsnmp_request_group *group = (netsnmp_request_group *) g;
  312.     if (!g)
  313.         return;
  314.     while (group->list) {
  315.         tmp = group->list;
  316.         group->list = tmp->next;
  317.         free(tmp);
  318.     }
  319.     free(group);
  320. }
  321. static void
  322. release_netsnmp_request_groups(void *vp)
  323. {
  324.     netsnmp_container *c = (netsnmp_container*)vp;
  325.     CONTAINER_FOR_EACH(c, (netsnmp_container_obj_func*)
  326.                        release_netsnmp_request_group, NULL);
  327.     CONTAINER_FREE(c);
  328. }
  329. void
  330. build_new_oid(netsnmp_handler_registration *reginfo,
  331.               netsnmp_table_request_info *tblreq_info,
  332.               netsnmp_index *row, netsnmp_request_info *current)
  333. {
  334.     oid             coloid[MAX_OID_LEN];
  335.     int             coloid_len;
  336.     if (!tblreq_info || !reginfo || !row || !current)
  337.         return;
  338.     coloid_len = reginfo->rootoid_len + 2;
  339.     memcpy(coloid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid));
  340.     /** table.entry */
  341.     coloid[reginfo->rootoid_len] = 1;
  342.     /** table.entry.column */
  343.     coloid[reginfo->rootoid_len + 1] = tblreq_info->colnum;
  344.     /** table.entry.column.index */
  345.     memcpy(&coloid[reginfo->rootoid_len + 2], row->oids,
  346.            row->len * sizeof(oid));
  347.     snmp_set_var_objid(current->requestvb, coloid,
  348.                        reginfo->rootoid_len + 2 + row->len);
  349. }
  350. /**********************************************************************
  351.  **********************************************************************
  352.  *                                                                    *
  353.  *                                                                    *
  354.  * GET procession functions                                           *
  355.  *                                                                    *
  356.  *                                                                    *
  357.  **********************************************************************
  358.  **********************************************************************/
  359. int
  360. process_get_requests(netsnmp_handler_registration *reginfo,
  361.                      netsnmp_agent_request_info *agtreq_info,
  362.                      netsnmp_request_info *requests,
  363.                      table_container_data * tad)
  364. {
  365.     int             rc = SNMP_ERR_NOERROR;
  366.     netsnmp_request_info *current;
  367.     netsnmp_index *row = NULL;
  368.     netsnmp_table_request_info *tblreq_info;
  369.     netsnmp_variable_list *var;
  370.     /*
  371.      * Loop through each of the requests, and
  372.      * try to find the appropriate row from the container.
  373.      */
  374.     for (current = requests; current; current = current->next) {
  375.         var = current->requestvb;
  376.         DEBUGMSGTL(("table_array:get",
  377.                     "  process_get_request oid:"));
  378.         DEBUGMSGOID(("table_array:get", var->name,
  379.                      var->name_length));
  380.         DEBUGMSG(("table_array:get", "n"));
  381.         /*
  382.          * skip anything that doesn't need processing.
  383.          */
  384.         if (current->processed != 0) {
  385.             DEBUGMSGTL(("table_array:get", "already processedn"));
  386.             continue;
  387.         }
  388.         /*
  389.          * Get pointer to the table information for this request. This
  390.          * information was saved by table_helper_handler. When
  391.          * debugging, we double check a few assumptions. For example,
  392.          * the table_helper_handler should enforce column boundaries.
  393.          */
  394.         tblreq_info = netsnmp_extract_table_info(current);
  395.         netsnmp_assert(tblreq_info->colnum <= tad->tblreg_info->max_column);
  396.         if ((agtreq_info->mode == MODE_GETNEXT) ||
  397.             (agtreq_info->mode == MODE_GETBULK)) {
  398.             /*
  399.              * find the row
  400.              */
  401.             row = netsnmp_table_index_find_next_row(tad->table, tblreq_info);
  402.             if (!row) {
  403.                 /*
  404.                  * no results found.
  405.                  *
  406.                  * xxx-rks: how do we skip this entry for the next handler,
  407.                  * but still allow it a chance to hit another handler?
  408.                  */
  409.                 DEBUGMSGTL(("table_array:get", "no row foundn"));
  410.                 netsnmp_set_request_error(agtreq_info, current,
  411.                                           SNMP_ENDOFMIBVIEW);
  412.                 continue;
  413.             }
  414.             /*
  415.              * * if data was found, make sure it has the column we want
  416.              */
  417. /* xxx-rks: add suport for sparse tables */
  418.             /*
  419.              * build new oid
  420.              */
  421.             build_new_oid(reginfo, tblreq_info, row, current);
  422.         } /** GETNEXT/GETBULK */
  423.         else {
  424.             netsnmp_index index;
  425.             index.oids = tblreq_info->index_oid;
  426.             index.len = tblreq_info->index_oid_len;
  427.             row = CONTAINER_FIND(tad->table, &index);
  428.             if (!row) {
  429.                 DEBUGMSGTL(("table_array:get", "no row foundn"));
  430.                 netsnmp_set_request_error(agtreq_info, current,
  431.                                           SNMP_NOSUCHINSTANCE);
  432.                 continue;
  433.             }
  434.         } /** GET */
  435.         /*
  436.          * get the data
  437.          */
  438.         rc = tad->cb->get_value(current, row, tblreq_info);
  439.     } /** for ( ... requests ... ) */
  440.     return rc;
  441. }
  442. /**********************************************************************
  443.  **********************************************************************
  444.  *                                                                    *
  445.  *                                                                    *
  446.  * SET procession functions                                           *
  447.  *                                                                    *
  448.  *                                                                    *
  449.  **********************************************************************
  450.  **********************************************************************/
  451. void
  452. group_requests(netsnmp_agent_request_info *agtreq_info,
  453.                netsnmp_request_info *requests,
  454.                netsnmp_container *request_group, table_container_data * tad)
  455. {
  456.     netsnmp_table_request_info *tblreq_info;
  457.     netsnmp_variable_list *var;
  458.     netsnmp_index *row, *tmp, index;
  459.     netsnmp_request_info *current;
  460.     netsnmp_request_group *g;
  461.     netsnmp_request_group_item *i;
  462.     for (current = requests; current; current = current->next) {
  463.         var = current->requestvb;
  464.         /*
  465.          * skip anything that doesn't need processing.
  466.          */
  467.         if (current->processed != 0) {
  468.             DEBUGMSGTL(("table_array:group",
  469.                         "already processedn"));
  470.             continue;
  471.         }
  472.         /*
  473.          * 3.2.1 Setup and paranoia
  474.          * *
  475.          * * Get pointer to the table information for this request. This
  476.          * * information was saved by table_helper_handler. When
  477.          * * debugging, we double check a few assumptions. For example,
  478.          * * the table_helper_handler should enforce column boundaries.
  479.          */
  480.         row = NULL;
  481.         tblreq_info = netsnmp_extract_table_info(current);
  482.         netsnmp_assert(tblreq_info->colnum <= tad->tblreg_info->max_column);
  483.         /*
  484.          * search for index
  485.          */
  486.         index.oids = tblreq_info->index_oid;
  487.         index.len = tblreq_info->index_oid_len;
  488.         tmp = CONTAINER_FIND(request_group, &index);
  489.         if (tmp) {
  490.             DEBUGMSGTL(("table_array:group",
  491.                         "    existing group:"));
  492.             DEBUGMSGOID(("table_array:group", index.oids,
  493.                          index.len));
  494.             DEBUGMSG(("table_array:group", "n"));
  495.             g = (netsnmp_request_group *) tmp;
  496.             i = SNMP_MALLOC_TYPEDEF(netsnmp_request_group_item);
  497.             i->ri = current;
  498.             i->tri = tblreq_info;
  499.             i->next = g->list;
  500.             g->list = i;
  501.             /** xxx-rks: store map of colnum to request */
  502.             continue;
  503.         }
  504.         DEBUGMSGTL(("table_array:group", "    new group"));
  505.         DEBUGMSGOID(("table_array:group", index.oids,
  506.                      index.len));
  507.         DEBUGMSG(("table_array:group", "n"));
  508.         g = SNMP_MALLOC_TYPEDEF(netsnmp_request_group);
  509.         i = SNMP_MALLOC_TYPEDEF(netsnmp_request_group_item);
  510.         g->list = i;
  511.         g->table = tad->table;
  512.         i->ri = current;
  513.         i->tri = tblreq_info;
  514.         /** xxx-rks: store map of colnum to request */
  515.         /*
  516.          * search for row. all changes are made to the original row,
  517.          * later, we'll make a copy in undo_info before we start processing.
  518.          */
  519.         row = g->existing_row = CONTAINER_FIND(tad->table, &index);
  520.         if (!g->existing_row) {
  521.             if (!tad->cb->create_row) {
  522.                 if(MODE_IS_SET(agtreq_info->mode))
  523.                     netsnmp_set_request_error(agtreq_info, current,
  524.                                               SNMP_ERR_NOTWRITABLE);
  525.                 else
  526.                     netsnmp_set_request_error(agtreq_info, current,
  527.                                               SNMP_NOSUCHINSTANCE);
  528.                 free(g);
  529.                 free(i);
  530.                 continue;
  531.             }
  532.             /** use undo_info temporarily */
  533.             row = g->existing_row = tad->cb->create_row(&index);
  534.             if (!row) {
  535.                 /* xxx-rks : parameter to create_row to allow
  536.                  * for better error reporting. */
  537.                 netsnmp_set_request_error(agtreq_info, current,
  538.                                           SNMP_ERR_GENERR);
  539.                 free(g);
  540.                 free(i);
  541.                 continue;
  542.             }
  543.             g->row_created = 1;
  544.         }
  545.         g->index.oids = row->oids;
  546.         g->index.len = row->len;
  547.         CONTAINER_INSERT(request_group, g);
  548.     } /** for( current ... ) */
  549. }
  550. static void
  551. process_set_group(netsnmp_index *o, void *c)
  552. {
  553.     /* xxx-rks: should we continue processing after an error?? */
  554.     set_context           *context = (set_context *) c;
  555.     netsnmp_request_group *ag = (netsnmp_request_group *) o;
  556.     int                    rc = SNMP_ERR_NOERROR;
  557.     switch (context->agtreq_info->mode) {
  558.     case MODE_SET_RESERVE1:/** -> SET_RESERVE2 || SET_FREE */
  559.         /*
  560.          * if not a new row, save undo info
  561.          */
  562.         if (ag->row_created == 0) {
  563.             if (context->tad->cb->duplicate_row)
  564.                 ag->undo_info = context->tad->cb->duplicate_row(ag->existing_row);
  565.             else
  566.                 ag->undo_info = NULL;
  567.             if (NULL == ag->undo_info) {
  568.                 rc = SNMP_ERR_RESOURCEUNAVAILABLE;
  569.                 break;
  570.             }
  571.         }
  572.         
  573.         if (context->tad->cb->set_reserve1)
  574.             context->tad->cb->set_reserve1(ag);
  575.         break;
  576.     case MODE_SET_RESERVE2:/** -> SET_ACTION || SET_FREE */
  577.         if (context->tad->cb->set_reserve2)
  578.             context->tad->cb->set_reserve2(ag);
  579.         break;
  580.     case MODE_SET_ACTION:/** -> SET_COMMIT || SET_UNDO */
  581.         if (context->tad->cb->set_action)
  582.             context->tad->cb->set_action(ag);
  583.         break;
  584.     case MODE_SET_COMMIT:/** FINAL CHANCE ON SUCCESS */
  585.         if (ag->row_created == 0) {
  586.             /*
  587.              * this is an existing row, has it been deleted?
  588.              */
  589.             if (ag->row_deleted == 1) {
  590.                 DEBUGMSGT((TABLE_ARRAY_NAME, "action: deleting rown"));
  591.                 if (CONTAINER_REMOVE(ag->table, ag->existing_row) != 0) {
  592.                     rc = SNMP_ERR_COMMITFAILED;
  593.                     break;
  594.                 }
  595.             }
  596.         } else if (ag->row_deleted == 0) {
  597.             /*
  598.              * new row (that hasn't been deleted) should be inserted
  599.              */
  600.             DEBUGMSGT((TABLE_ARRAY_NAME, "action: inserting rown"));
  601.             if (CONTAINER_INSERT(ag->table, ag->existing_row) != 0) {
  602.                 rc = SNMP_ERR_COMMITFAILED;
  603.                 break;
  604.             }
  605.         }
  606.         if (context->tad->cb->set_commit)
  607.             context->tad->cb->set_commit(ag);
  608.         /** no more use for undo_info, so free it */
  609.         if (ag->undo_info) {
  610.             context->tad->cb->delete_row(ag->undo_info);
  611.             ag->undo_info = NULL;
  612.         }
  613. #if 0
  614.         /* XXX-rks: finish row cooperative notifications
  615.          * if the table has requested it, send cooperative notifications
  616.          * for row operations.
  617.          */
  618.         if (context->tad->notifications) {
  619.             if (ag->undo_info) {
  620.                 if (!ag->existing_row)
  621.                     netsnmp_monitor_notify(EVENT_ROW_DEL);
  622.                 else
  623.                     netsnmp_monitor_notify(EVENT_ROW_MOD);
  624.             }
  625.             else
  626.                 netsnmp_monitor_notify(EVENT_ROW_ADD);
  627.         }
  628. #endif
  629.         if ((ag->row_created == 0) && (ag->row_deleted == 1)) {
  630.             context->tad->cb->delete_row(ag->existing_row);
  631.             ag->existing_row = NULL;
  632.         }
  633.         break;
  634.     case MODE_SET_FREE:/** FINAL CHANCE ON FAILURE */
  635.         if (context->tad->cb->set_free)
  636.             context->tad->cb->set_free(ag);
  637.         /** no more use for undo_info, so free it */
  638.         if (ag->row_created == 1) {
  639.             if (context->tad->cb->delete_row)
  640.                 context->tad->cb->delete_row(ag->existing_row);
  641.             ag->existing_row = NULL;
  642.         }
  643.         else {
  644.             if (context->tad->cb->delete_row)
  645.                 context->tad->cb->delete_row(ag->undo_info);
  646.             ag->undo_info = NULL;
  647.         }
  648.         break;
  649.     case MODE_SET_UNDO:/** FINAL CHANCE ON FAILURE */
  650.         /*
  651.          * status already set - don't change it now
  652.          */
  653.         if (context->tad->cb->set_undo)
  654.             context->tad->cb->set_undo(ag);
  655.         /*
  656.          * no more use for undo_info, so free it
  657.          */
  658.         if (ag->row_created == 0) {
  659.             /*
  660.              * restore old values
  661.              */
  662.             context->tad->cb->row_copy(ag->existing_row, ag->undo_info);
  663.             context->tad->cb->delete_row(ag->undo_info);
  664.             ag->undo_info = NULL;
  665.         }
  666.         else {
  667.             context->tad->cb->delete_row(ag->existing_row);
  668.             ag->existing_row = NULL;
  669.         }
  670.         break;
  671.     default:
  672.         snmp_log(LOG_ERR, "unknown mode processing SET for "
  673.                  "netsnmp_table_array_helper_handlern");
  674.         rc = SNMP_ERR_GENERR;
  675.         break;
  676.     }
  677.     
  678.     if (rc)
  679.         netsnmp_set_request_error(context->agtreq_info,
  680.                                   ag->list->ri, rc);
  681.                                                
  682. }
  683. int
  684. process_set_requests(netsnmp_agent_request_info *agtreq_info,
  685.                      netsnmp_request_info *requests,
  686.                      table_container_data * tad, char *handler_name)
  687. {
  688.     set_context         context;
  689.     netsnmp_container  *request_group;
  690.     /*
  691.      * create and save structure for set info
  692.      */
  693.     request_group = (netsnmp_container*) netsnmp_agent_get_list_data
  694.         (agtreq_info, handler_name);
  695.     if (request_group == NULL) {
  696.         netsnmp_data_list *tmp;
  697.         request_group = netsnmp_container_find("request_group:"
  698.                                                "table_container");
  699.         request_group->compare = netsnmp_compare_netsnmp_index;
  700.         request_group->ncompare = netsnmp_ncompare_netsnmp_index;
  701.         DEBUGMSGTL(("table_array", "Grouping requests by oidn"));
  702.         tmp = netsnmp_create_data_list(handler_name,
  703.                                        request_group,
  704.                                        release_netsnmp_request_groups);
  705.         netsnmp_agent_add_list_data(agtreq_info, tmp);
  706.         /*
  707.          * group requests.
  708.          */
  709.         group_requests(agtreq_info, requests, request_group, tad);
  710.     }
  711.     /*
  712.      * process each group one at a time
  713.      */
  714.     context.agtreq_info = agtreq_info;
  715.     context.tad = tad;
  716.     context.status = SNMP_ERR_NOERROR;
  717.     CONTAINER_FOR_EACH(request_group,
  718.                        (netsnmp_container_obj_func*)process_set_group,
  719.                        &context);
  720.     return context.status;
  721. }
  722. /**********************************************************************
  723.  **********************************************************************
  724.  *                                                                    *
  725.  *                                                                    *
  726.  * netsnmp_table_array_helper_handler()                               *
  727.  *                                                                    *
  728.  *                                                                    *
  729.  **********************************************************************
  730.  **********************************************************************/
  731. int
  732. netsnmp_table_array_helper_handler(netsnmp_mib_handler *handler,
  733.                                    netsnmp_handler_registration *reginfo,
  734.                                    netsnmp_agent_request_info *agtreq_info,
  735.                                    netsnmp_request_info *requests)
  736. {
  737.     /*
  738.      * First off, get our pointer from the handler. This
  739.      * lets us get to the table registration information we
  740.      * saved in get_table_array_handler(), as well as the
  741.      * container where the actual table data is stored.
  742.      */
  743.     int             rc = SNMP_ERR_NOERROR;
  744.     table_container_data *tad = (table_container_data *)handler->myvoid;
  745.     if (agtreq_info->mode < 0 || agtreq_info->mode > 5) {
  746.         DEBUGMSGTL(("table_array", "Mode %d, Got request:n",
  747.                     agtreq_info->mode));
  748.     } else {
  749.         DEBUGMSGTL(("table_array", "Mode %s, Got request:n",
  750.                     mode_name[agtreq_info->mode]));
  751.     }
  752.     if (MODE_IS_SET(agtreq_info->mode)) {
  753.         /*
  754.          * netsnmp_mutex_lock(&tad->lock);
  755.          */
  756.         rc = process_set_requests(agtreq_info, requests,
  757.                                   tad, handler->handler_name);
  758.         /*
  759.          * netsnmp_mutex_unlock(&tad->lock);
  760.          */
  761.     } else
  762.         rc = process_get_requests(reginfo, agtreq_info, requests, tad);
  763.     if (rc != SNMP_ERR_NOERROR) {
  764.         DEBUGMSGTL(("table_array", "processing returned rc %dn", rc));
  765.     }
  766.     
  767.     /*
  768.      * Now we've done our processing. If there is another handler below us,
  769.      * call them.
  770.      */
  771.     if (handler->next) {
  772.         rc = netsnmp_call_next_handler(handler, reginfo, agtreq_info, requests);
  773.         if (rc != SNMP_ERR_NOERROR) {
  774.             DEBUGMSGTL(("table_array", "next handler returned rc %dn", rc));
  775.         }
  776.     }
  777.     
  778.     return rc;
  779. }
  780. #endif /** DOXYGEN_SHOULD_SKIP_THIS */