table_dataset.c

00001 #include <net-snmp/net-snmp-config.h>
00002 
00003 #if HAVE_STRING_H
00004 #include <string.h>
00005 #else
00006 #include <strings.h>
00007 #endif
00008 
00009 #include <net-snmp/net-snmp-includes.h>
00010 #include <net-snmp/agent/net-snmp-agent-includes.h>
00011 
00012 static netsnmp_data_list *auto_tables;
00013 
00014 typedef struct data_set_tables_s {
00015     netsnmp_table_data_set *table_set;
00016 } data_set_tables;
00017 
00018 typedef struct data_set_cache_s {
00019     void           *data;
00020     size_t          data_len;
00021 } data_set_cache;
00022 
00023 #define STATE_ACTION   1
00024 #define STATE_COMMIT   2
00025 #define STATE_UNDO     3
00026 #define STATE_FREE     4
00027 
00028 typedef struct newrow_stash_s {
00029     netsnmp_table_row *newrow;
00030     int             state;
00031     int             created;
00032     int             deleted;
00033 } newrow_stash;
00034 
00061 void
00062 netsnmp_init_table_dataset(void) {
00063 #ifndef DISABLE_MIB_LOADING
00064     register_app_config_handler("table",
00065                                 netsnmp_config_parse_table_set, NULL,
00066                                 "tableoid");
00067 #endif /* DISABLE_MIB_LOADING */
00068     register_app_config_handler("add_row", netsnmp_config_parse_add_row,
00069                                 NULL, "table_name indexes... values...");
00070 }
00071 
00072 /* ==================================
00073  *
00074  * Data Set API: Table maintenance
00075  *
00076  * ================================== */
00077 
00079 netsnmp_table_data_set *
00080 netsnmp_create_table_data_set(const char *table_name)
00081 {
00082     netsnmp_table_data_set *table_set =
00083         SNMP_MALLOC_TYPEDEF(netsnmp_table_data_set);
00084     if (!table_set)
00085         return NULL;
00086     table_set->table = netsnmp_create_table_data(table_name);
00087     return table_set;
00088 }
00089 
00091 netsnmp_table_row *
00092 netsnmp_table_data_set_clone_row(netsnmp_table_row *row)
00093 {
00094     netsnmp_table_data_set_storage *data, **newrowdata;
00095     netsnmp_table_row *newrow;
00096 
00097     if (!row)
00098         return NULL;
00099 
00100     newrow = netsnmp_table_data_clone_row(row);
00101     if (!newrow)
00102         return NULL;
00103 
00104     data = (netsnmp_table_data_set_storage *) row->data;
00105 
00106     if (data) {
00107         for (newrowdata =
00108              (netsnmp_table_data_set_storage **) &(newrow->data); data;
00109              newrowdata = &((*newrowdata)->next), data = data->next) {
00110 
00111             memdup((u_char **) newrowdata, (u_char *) data,
00112                    sizeof(netsnmp_table_data_set_storage));
00113             if (!*newrowdata) {
00114                 netsnmp_table_dataset_delete_row(newrow);
00115                 return NULL;
00116             }
00117 
00118             if (data->data.voidp) {
00119                 memdup((u_char **) & ((*newrowdata)->data.voidp),
00120                        (u_char *) data->data.voidp, data->data_len);
00121                 if (!(*newrowdata)->data.voidp) {
00122                     netsnmp_table_dataset_delete_row(newrow);
00123                     return NULL;
00124                 }
00125             }
00126         }
00127     }
00128     return newrow;
00129 }
00130 
00134 NETSNMP_INLINE netsnmp_table_data_set_storage *
00135 netsnmp_table_dataset_delete_data(netsnmp_table_data_set_storage *data)
00136 {
00137     netsnmp_table_data_set_storage *nextPtr = NULL;
00138     if (data) {
00139         nextPtr = data->next;
00140         SNMP_FREE(data->data.voidp);
00141     }
00142     SNMP_FREE(data);
00143     return nextPtr;
00144 }
00145 
00147 NETSNMP_INLINE void
00148 netsnmp_table_dataset_delete_all_data(netsnmp_table_data_set_storage *data)
00149 {
00150 
00151     while (data) {
00152         data = netsnmp_table_dataset_delete_data(data);
00153     }
00154 }
00155 
00157 NETSNMP_INLINE void
00158 netsnmp_table_dataset_delete_row(netsnmp_table_row *row)
00159 {
00160     netsnmp_table_data_set_storage *data;
00161 
00162     if (!row)
00163         return;
00164 
00165     data = netsnmp_table_data_delete_row(row);
00166     netsnmp_table_dataset_delete_all_data(data);
00167 }
00168 
00170 NETSNMP_INLINE void
00171 netsnmp_table_dataset_add_row(netsnmp_table_data_set *table,
00172                               netsnmp_table_row *row)
00173 {
00174     if (!table)
00175         return;
00176     netsnmp_table_data_add_row(table->table, row);
00177 }
00178 
00180 NETSNMP_INLINE void
00181 netsnmp_table_dataset_replace_row(netsnmp_table_data_set *table,
00182                                   netsnmp_table_row *origrow,
00183                                   netsnmp_table_row *newrow)
00184 {
00185     if (!table)
00186         return;
00187     netsnmp_table_data_replace_row(table->table, origrow, newrow);
00188 }
00189 
00191 NETSNMP_INLINE void
00192 netsnmp_table_dataset_remove_row(netsnmp_table_data_set *table,
00193                                  netsnmp_table_row *row)
00194 {
00195     if (!table)
00196         return;
00197 
00198     netsnmp_table_data_remove_and_delete_row(table->table, row);
00199 }
00200 
00202 NETSNMP_INLINE void
00203 netsnmp_table_dataset_remove_and_delete_row(netsnmp_table_data_set *table,
00204                                             netsnmp_table_row *row)
00205 {
00206     netsnmp_table_data_set_storage *data;
00207 
00208     if (!table)
00209         return;
00210 
00211     data = (netsnmp_table_data_set_storage *)
00212         netsnmp_table_data_remove_and_delete_row(table->table, row);
00213 
00214     netsnmp_table_dataset_delete_all_data(data);
00215 }
00216 
00217 /* ==================================
00218  *
00219  * Data Set API: Default row operations
00220  *
00221  * ================================== */
00222 
00224 netsnmp_table_row *
00225 netsnmp_table_data_set_create_row_from_defaults
00226     (netsnmp_table_data_set_storage *defrow)
00227 {
00228     netsnmp_table_row *row;
00229     row = netsnmp_create_table_data_row();
00230     if (!row)
00231         return NULL;
00232     for (; defrow; defrow = defrow->next) {
00233         netsnmp_set_row_column(row, defrow->column, defrow->type,
00234                                defrow->data.voidp, defrow->data_len);
00235         if (defrow->writable)
00236             netsnmp_mark_row_column_writable(row, defrow->column, 1);
00237 
00238     }
00239     return row;
00240 }
00241 
00251 int
00252 netsnmp_table_set_add_default_row(netsnmp_table_data_set *table_set,
00253                                   unsigned int column,
00254                                   int type, int writable,
00255                                   void *default_value,
00256                                   size_t default_value_len)
00257 {
00258     netsnmp_table_data_set_storage *new_col, *ptr, *pptr;
00259 
00260     if (!table_set)
00261         return SNMPERR_GENERR;
00262 
00263     /*
00264      * double check 
00265      */
00266     new_col =
00267         netsnmp_table_data_set_find_column(table_set->default_row, column);
00268     if (new_col != NULL) {
00269         if (new_col->type == type && new_col->writable == writable)
00270             return SNMPERR_SUCCESS;
00271         return SNMPERR_GENERR;
00272     }
00273 
00274     new_col = SNMP_MALLOC_TYPEDEF(netsnmp_table_data_set_storage);
00275     new_col->type = type;
00276     new_col->writable = writable;
00277     new_col->column = column;
00278     if (default_value) {
00279         memdup((u_char **) & (new_col->data.voidp),
00280                (u_char *) default_value, default_value_len);
00281         new_col->data_len = default_value_len;
00282     }
00283     if (table_set->default_row == NULL)
00284         table_set->default_row = new_col;
00285     else {
00286         /* sort in order just because (needed for add_row support) */
00287         for (ptr = table_set->default_row, pptr = NULL;
00288              ptr;
00289              pptr = ptr, ptr = ptr->next) {
00290             if (ptr->column > column) {
00291                 new_col->next = ptr;
00292                 if (pptr)
00293                     pptr->next = new_col;
00294                 else
00295                     table_set->default_row = new_col;
00296                 return SNMPERR_SUCCESS;
00297             }
00298         }
00299         if (pptr)
00300             pptr->next = new_col;
00301         else
00302             snmp_log(LOG_ERR,"Shouldn't have gotten here: table_dataset/add_row");
00303     }
00304     return SNMPERR_SUCCESS;
00305 }
00306 
00311 void
00312 #if HAVE_STDARG_H
00313 netsnmp_table_set_multi_add_default_row(netsnmp_table_data_set *tset, ...)
00314 #else
00315 netsnmp_table_set_multi_add_default_row(va_dcl
00316     )
00317      va_dcl
00318 #endif
00319 {
00320     va_list         debugargs;
00321     unsigned int    column;
00322     int             type, writable;
00323     void           *data;
00324     size_t          data_len;
00325 
00326 #if HAVE_STDARG_H
00327     va_start(debugargs, tset);
00328 #else
00329     netsnmp_table_data_set *tset;
00330 
00331     va_start(debugargs);
00332     tset = va_arg(debugargs, netsnmp_table_data_set *);
00333 #endif
00334 
00335     while ((column = va_arg(debugargs, unsigned int)) != 0) {
00336         type = va_arg(debugargs, int);
00337         writable = va_arg(debugargs, int);
00338         data = va_arg(debugargs, void *);
00339         data_len = va_arg(debugargs, size_t);
00340         netsnmp_table_set_add_default_row(tset, column, type, writable,
00341                                           data, data_len);
00342     }
00343 
00344     va_end(debugargs);
00345 }
00346 
00347 
00348 /* ==================================
00349  *
00350  * Data Set API: MIB maintenance
00351  *
00352  * ================================== */
00353 
00355 netsnmp_mib_handler *
00356 netsnmp_get_table_data_set_handler(netsnmp_table_data_set *data_set)
00357 {
00358     netsnmp_mib_handler *ret = NULL;
00359 
00360     if (!data_set) {
00361         snmp_log(LOG_INFO,
00362                  "netsnmp_get_table_data_set_handler(NULL) called\n");
00363         return NULL;
00364     }
00365 
00366     ret =
00367         netsnmp_create_handler(TABLE_DATA_SET_NAME,
00368                                netsnmp_table_data_set_helper_handler);
00369     if (ret) {
00370         ret->flags |= MIB_HANDLER_AUTO_NEXT;
00371         ret->myvoid = (void *) data_set;
00372     }
00373     return ret;
00374 }
00375 
00381 int
00382 netsnmp_register_table_data_set(netsnmp_handler_registration *reginfo,
00383                                 netsnmp_table_data_set *data_set,
00384                                 netsnmp_table_registration_info *table_info)
00385 {
00386     if (NULL == table_info) {
00387         /*
00388          * allocate the table if one wasn't allocated 
00389          */
00390         table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
00391     }
00392 
00393     if (NULL == table_info->indexes && data_set->table->indexes_template) {
00394         /*
00395          * copy the indexes in 
00396          */
00397         table_info->indexes =
00398             snmp_clone_varbind(data_set->table->indexes_template);
00399     }
00400 
00401     if ((!table_info->min_column || !table_info->max_column) &&
00402         (data_set->default_row)) {
00403         /*
00404          * determine min/max columns 
00405          */
00406         unsigned int    mincol = 0xffffffff, maxcol = 0;
00407         netsnmp_table_data_set_storage *row;
00408 
00409         for (row = data_set->default_row; row; row = row->next) {
00410             mincol = SNMP_MIN(mincol, row->column);
00411             maxcol = SNMP_MAX(maxcol, row->column);
00412         }
00413         if (!table_info->min_column)
00414             table_info->min_column = mincol;
00415         if (!table_info->max_column)
00416             table_info->max_column = maxcol;
00417     }
00418 
00419     netsnmp_inject_handler(reginfo,
00420                            netsnmp_get_table_data_set_handler(data_set));
00421     return netsnmp_register_table_data(reginfo, data_set->table,
00422                                        table_info);
00423 }
00424 
00425 newrow_stash   *
00426 netsnmp_table_data_set_create_newrowstash
00427     (netsnmp_table_data_set     *datatable,
00428      netsnmp_table_request_info *table_info)
00429 {
00430     newrow_stash   *newrowstash = NULL;
00431     netsnmp_table_row *newrow   = NULL;
00432 
00433     newrowstash = SNMP_MALLOC_TYPEDEF(newrow_stash);
00434     newrowstash->created = 1;
00435     newrow = netsnmp_table_data_set_create_row_from_defaults
00436                         (datatable->default_row);
00437     newrow->indexes = snmp_clone_varbind(table_info->indexes);
00438     newrowstash->newrow = newrow;
00439 
00440     return newrowstash;
00441 }
00442 
00443 /* implements the table data helper.  This is the routine that takes
00444  *  care of all SNMP requests coming into the table. */
00445 int
00446 netsnmp_table_data_set_helper_handler(netsnmp_mib_handler *handler,
00447                                       netsnmp_handler_registration
00448                                       *reginfo,
00449                                       netsnmp_agent_request_info *reqinfo,
00450                                       netsnmp_request_info *requests)
00451 {
00452     netsnmp_table_data_set_storage *data = NULL;
00453     newrow_stash   *newrowstash = NULL;
00454     netsnmp_table_row *row, *newrow = NULL;
00455     netsnmp_table_request_info *table_info;
00456     netsnmp_request_info *request;
00457     oid            *suffix;
00458     size_t          suffix_len;
00459     netsnmp_oid_stash_node **stashp = NULL;
00460 
00461     if (!handler)
00462         return SNMPERR_GENERR;
00463         
00464     DEBUGMSGTL(("netsnmp_table_data_set", "handler starting\n"));
00465     for (request = requests; request; request = request->next) {
00466         netsnmp_table_data_set *datatable =
00467             (netsnmp_table_data_set *) handler->myvoid;
00468         if (request->processed)
00469             continue;
00470 
00471         /*
00472          * extract our stored data and table info 
00473          */
00474         row = netsnmp_extract_table_row(request);
00475         table_info = netsnmp_extract_table_info(request);
00476         suffix = requests->requestvb->name + reginfo->rootoid_len + 2;
00477         suffix_len = requests->requestvb->name_length -
00478             (reginfo->rootoid_len + 2);
00479 
00480         if (MODE_IS_SET(reqinfo->mode)) {
00481 
00482             char buf[256]; /* is this reasonable size?? */
00483             int  rc;
00484             size_t len;
00485 
00486             /*
00487              * use a cached copy of the row for modification 
00488              */
00489 
00490             /*
00491              * cache location: may have been created already by other
00492              * SET requests in the same master request. 
00493              */
00494             rc = snprintf(buf, sizeof(buf), "dataset_row_stash:%s:",
00495                           datatable->table->name);
00496             if ((-1 == rc) || (rc >= sizeof(buf))) {
00497                 snmp_log(LOG_ERR,"%s handler name too long\n",
00498                          datatable->table->name);
00499                 netsnmp_set_request_error(reqinfo, request,
00500                                           SNMP_ERR_GENERR);
00501                 continue;
00502             }
00503             len = sizeof(buf) - rc;
00504             rc = snprint_objid(&buf[rc], len, table_info->index_oid,
00505                                table_info->index_oid_len);
00506             if (-1 == rc) {
00507                 snmp_log(LOG_ERR,"%s oid or name too long\n",
00508                          datatable->table->name);
00509                 netsnmp_set_request_error(reqinfo, request,
00510                                           SNMP_ERR_GENERR);
00511                 continue;
00512             }
00513             stashp = (netsnmp_oid_stash_node **)
00514                 netsnmp_table_get_or_create_row_stash(reqinfo, buf);
00515 
00516             newrowstash
00517                 = netsnmp_oid_stash_get_data(*stashp, suffix, suffix_len);
00518 
00519             if (!newrowstash) {
00520                 if (!row) {
00521                     if (datatable->allow_creation) {
00522                         /*
00523                          * entirely new row.  Create the row from the template 
00524                          */
00525                         newrowstash =
00526                              netsnmp_table_data_set_create_newrowstash(
00527                                                  datatable, table_info);
00528                         newrow = newrowstash->newrow;
00529                     } else if (datatable->rowstatus_column == 0) {
00530                         /*
00531                          * A RowStatus object may be used to control the
00532                          *  creation of a new row.  But if this object
00533                          *  isn't declared (and the table isn't marked as
00534                          *  'auto-create'), then we can't create a new row.
00535                          */
00536                         netsnmp_set_request_error(reqinfo, request,
00537                                                   SNMP_ERR_NOCREATION);
00538                         continue;
00539                     }
00540                 } else {
00541                     /*
00542                      * existing row that needs to be modified 
00543                      */
00544                     newrowstash = SNMP_MALLOC_TYPEDEF(newrow_stash);
00545                     newrow = netsnmp_table_data_set_clone_row(row);
00546                     newrowstash->newrow = newrow;
00547                 }
00548                 netsnmp_oid_stash_add_data(stashp, suffix, suffix_len,
00549                                            newrowstash);
00550             } else {
00551                 newrow = newrowstash->newrow;
00552             }
00553             /*
00554              * all future SET data modification operations use this
00555              * temp pointer 
00556              */
00557             if (reqinfo->mode == MODE_SET_RESERVE1 ||
00558                 reqinfo->mode == MODE_SET_RESERVE2)
00559                 row = newrow;
00560         }
00561 
00562         if (row)
00563             data = (netsnmp_table_data_set_storage *) row->data;
00564 
00565         if (!row || !table_info || !data) {
00566             if (!MODE_IS_SET(reqinfo->mode)) {
00567                 netsnmp_set_request_error(reqinfo, request,
00568                                           SNMP_NOSUCHINSTANCE);
00569                 continue;
00570             }
00571         }
00572 
00573         data =
00574             netsnmp_table_data_set_find_column(data, table_info->colnum);
00575 
00576         switch (reqinfo->mode) {
00577         case MODE_GET:
00578         case MODE_GETNEXT:
00579         case MODE_GETBULK:     /* XXXWWW */
00580             if (data && data->data.voidp)
00581                 netsnmp_table_data_build_result(reginfo, reqinfo, request,
00582                                                 row,
00583                                                 table_info->colnum,
00584                                                 data->type,
00585                                                 data->data.voidp,
00586                                                 data->data_len);
00587             break;
00588 
00589         case MODE_SET_RESERVE1:
00590             if (data) {
00591                 /*
00592                  * Can we modify the existing row?
00593                  */
00594                 if (!data->writable) {
00595                     netsnmp_set_request_error(reqinfo, request,
00596                                               SNMP_ERR_NOTWRITABLE);
00597                 } else if (request->requestvb->type != data->type) {
00598                     netsnmp_set_request_error(reqinfo, request,
00599                                               SNMP_ERR_WRONGTYPE);
00600                 }
00601             } else if (datatable->rowstatus_column == table_info->colnum) {
00602                 /*
00603                  * Otherwise, this is where we create a new row using
00604                  * the RowStatus object (essentially duplicating the
00605                  * steps followed earlier in the 'allow_creation' case)
00606                  */
00607                 switch (*(request->requestvb->val.integer)) {
00608                 case RS_CREATEANDGO:
00609                 case RS_CREATEANDWAIT:
00610                     newrowstash =
00611                              netsnmp_table_data_set_create_newrowstash(
00612                                                  datatable, table_info);
00613                     newrow = newrowstash->newrow;
00614                     row    = newrow;
00615                     netsnmp_oid_stash_add_data(stashp, suffix, suffix_len,
00616                                                newrowstash);
00617                 }
00618             }
00619             break;
00620 
00621         case MODE_SET_RESERVE2:
00622             /*
00623              * If the agent receives a SET request for an object in a non-existant
00624              *  row, then the RESERVE1 pass will create the row automatically.
00625              *
00626              * But since the row doesn't exist at that point, the test for whether
00627              *  the object is writable or not will be skipped.  So we need to check
00628              *  for this possibility again here.
00629              *
00630              * Similarly, if row creation is under the control of the RowStatus
00631              *  object (i.e. allow_creation == 0), but this particular request
00632              *  doesn't include such an object, then the row won't have been created,
00633              *  and the writable check will also have been skipped.  Again - check here.
00634              */
00635             if (data && data->writable == 0) {
00636                 netsnmp_set_request_error(reqinfo, request,
00637                                           SNMP_ERR_NOTWRITABLE);
00638                 continue;
00639             }
00640             if (datatable->rowstatus_column == table_info->colnum) {
00641                 switch (*(request->requestvb->val.integer)) {
00642                 case RS_ACTIVE:
00643                 case RS_NOTINSERVICE:
00644                     /*
00645                      * Can only operate on pre-existing rows.
00646                      */
00647                     if (!newrowstash || newrowstash->created) {
00648                         netsnmp_set_request_error(reqinfo, request,
00649                                                   SNMP_ERR_INCONSISTENTVALUE);
00650                         continue;
00651                     }
00652                     break;
00653 
00654                 case RS_CREATEANDGO:
00655                 case RS_CREATEANDWAIT:
00656                     /*
00657                      * Can only operate on newly created rows.
00658                      */
00659                     if (!(newrowstash && newrowstash->created)) {
00660                         netsnmp_set_request_error(reqinfo, request,
00661                                                   SNMP_ERR_INCONSISTENTVALUE);
00662                         continue;
00663                     }
00664                     break;
00665 
00666                 case RS_DESTROY:
00667                     /*
00668                      * Can operate on new or pre-existing rows.
00669                      */
00670                     break;
00671 
00672                 case RS_NOTREADY:
00673                 default:
00674                     /*
00675                      * Not a valid value to Set 
00676                      */
00677                     netsnmp_set_request_error(reqinfo, request,
00678                                               SNMP_ERR_WRONGVALUE);
00679                     continue;
00680                 }
00681             }
00682             if (!data ) {
00683                 netsnmp_set_request_error(reqinfo, request,
00684                                           SNMP_ERR_NOCREATION);
00685                 continue;
00686             }
00687 
00688             /*
00689              * modify row and set new value 
00690              */
00691             SNMP_FREE(data->data.string);
00692             data->data.string =
00693                 netsnmp_strdup_and_null(request->requestvb->val.string,
00694                                         request->requestvb->val_len);
00695             if (!data->data.string) {
00696                 netsnmp_set_request_error(reqinfo, requests,
00697                                           SNMP_ERR_RESOURCEUNAVAILABLE);
00698             }
00699             data->data_len = request->requestvb->val_len;
00700 
00701             if (datatable->rowstatus_column == table_info->colnum) {
00702                 switch (*(request->requestvb->val.integer)) {
00703                 case RS_CREATEANDGO:
00704                     /*
00705                      * XXX: check legality 
00706                      */
00707                     *(data->data.integer) = RS_ACTIVE;
00708                     break;
00709 
00710                 case RS_CREATEANDWAIT:
00711                     /*
00712                      * XXX: check legality 
00713                      */
00714                     *(data->data.integer) = RS_NOTINSERVICE;
00715                     break;
00716 
00717                 case RS_DESTROY:
00718                     newrowstash->deleted = 1;
00719                     break;
00720                 }
00721             }
00722             break;
00723 
00724         case MODE_SET_ACTION:
00725 
00726             /*
00727              * Install the new row into the stored table.
00728              * Do this only *once* per row ....
00729              */
00730             if (newrowstash->state != STATE_ACTION) {
00731                 newrowstash->state = STATE_ACTION;
00732                 if (newrowstash->created) {
00733                     netsnmp_table_dataset_add_row(datatable, newrow);
00734                 } else {
00735                     netsnmp_table_dataset_replace_row(datatable,
00736                                                       row, newrow);
00737                 }
00738             }
00739             /*
00740              * ... but every (relevant) varbind in the request will
00741              * need to know about this new row, so update the
00742              * per-request row information regardless
00743              */
00744             if (newrowstash->created) {
00745                 netsnmp_request_add_list_data(request,
00746                         netsnmp_create_data_list(TABLE_DATA_NAME,
00747                                                  newrow, NULL));
00748             }
00749             break;
00750 
00751         case MODE_SET_UNDO:
00752             /*
00753              * extract the new row, replace with the old or delete 
00754              */
00755             if (newrowstash->state != STATE_UNDO) {
00756                 newrowstash->state = STATE_UNDO;
00757                 if (newrowstash->created) {
00758                     netsnmp_table_dataset_remove_and_delete_row(datatable, newrow);
00759                 } else {
00760                     netsnmp_table_dataset_replace_row(datatable,
00761                                                       newrow, row);
00762                     netsnmp_table_dataset_delete_row(newrow);
00763                 }
00764                 newrow = NULL;
00765             }
00766             break;
00767 
00768         case MODE_SET_COMMIT:
00769             if (newrowstash->state != STATE_COMMIT) {
00770                 newrowstash->state = STATE_COMMIT;
00771                 if (!newrowstash->created) {
00772                     netsnmp_request_info       *req;
00773                     netsnmp_table_dataset_delete_row(row);
00774 
00775                     /* Walk the request list to update the reference to the old row w/ th new one */
00776                     for (req = requests; req; req=req->next) {
00777         
00778                         /*
00779                                 * For requests that have the old row values,
00780                                 * so add the newly-created row information.
00781                         */
00782                         if ((netsnmp_table_row *) netsnmp_extract_table_row(req) == row) {
00783                                 netsnmp_request_remove_list_data(req, TABLE_DATA_ROW);
00784                                 netsnmp_request_add_list_data(req,
00785                                     netsnmp_create_data_list(TABLE_DATA_ROW, newrow, NULL));
00786                         }
00787                     }
00788 
00789                     row = NULL;
00790                 }
00791                 if (newrowstash->deleted) {
00792                     netsnmp_table_dataset_remove_and_delete_row(datatable, newrow);
00793                     newrow = NULL;
00794                 }
00795             }
00796             break;
00797 
00798         case MODE_SET_FREE:
00799             if (newrowstash && newrowstash->state != STATE_FREE) {
00800                 newrowstash->state = STATE_FREE;
00801                 netsnmp_table_dataset_delete_row(newrow);
00802                 newrow = NULL;
00803             }
00804             break;
00805         }
00806     }
00807 
00808     /* next handler called automatically - 'AUTO_NEXT' */
00809     return SNMP_ERR_NOERROR;
00810 }
00811 
00815 NETSNMP_INLINE netsnmp_table_data_set *
00816 netsnmp_extract_table_data_set(netsnmp_request_info *request)
00817 {
00818     return (netsnmp_table_data_set *)
00819         netsnmp_request_get_list_data(request, TABLE_DATA_SET_NAME);
00820 }
00821 
00825 netsnmp_table_data_set_storage *
00826 netsnmp_extract_table_data_set_column(netsnmp_request_info *request,
00827                                      unsigned int column)
00828 {
00829     netsnmp_table_data_set_storage *data =
00830         netsnmp_extract_table_row_data( request );
00831     if (data) {
00832         data = netsnmp_table_data_set_find_column(data, column);
00833     }
00834     return data;
00835 }
00836 
00837 
00838 /* ==================================
00839  *
00840  * Data Set API: Config-based operation
00841  *
00842  * ================================== */
00843 
00852 void
00853 netsnmp_register_auto_data_table(netsnmp_table_data_set *table_set,
00854                                  char *registration_name)
00855 {
00856     data_set_tables *tables;
00857     tables = SNMP_MALLOC_TYPEDEF(data_set_tables);
00858     if (!tables)
00859         return;
00860     tables->table_set = table_set;
00861     if (!registration_name) {
00862         registration_name = table_set->table->name;
00863     }
00864     netsnmp_add_list_data(&auto_tables, netsnmp_create_data_list(registration_name, tables, NULL));     /* XXX */
00865 }
00866 
00867 #ifndef DISABLE_MIB_LOADING
00868 static void
00869 _table_set_add_indexes(netsnmp_table_data_set *table_set, struct tree *tp)
00870 {
00871     oid             name[MAX_OID_LEN];
00872     size_t          name_length = MAX_OID_LEN;
00873     struct index_list *index;
00874     struct tree     *indexnode;
00875     u_char          type;
00876     
00877     /*
00878      * loop through indexes and add types 
00879      */
00880     for (index = tp->indexes; index; index = index->next) {
00881         if (!snmp_parse_oid(index->ilabel, name, &name_length) ||
00882             (NULL ==
00883              (indexnode = get_tree(name, name_length, get_tree_head())))) {
00884             config_pwarn("can't instatiate table since "
00885                          "I don't know anything about one index");
00886             snmp_log(LOG_WARNING, "  index %s not found in tree\n",
00887                      index->ilabel);
00888             return;             /* xxx mem leak */
00889         }
00890             
00891         type = mib_to_asn_type(indexnode->type);
00892         if (type == (u_char) - 1) {
00893             config_pwarn("unknown index type");
00894             return;             /* xxx mem leak */
00895         }
00896         /*
00897          * if implied, mark it as such. also mark fixed length
00898          * octet strings as implied (ie no length prefix) as well.
00899          * */
00900         if ((index->isimplied) ||
00901             ((TYPE_OCTETSTR == indexnode->type) &&  /* octet str */
00902              (NULL != indexnode->ranges) &&         /* & has range */
00903              (NULL == indexnode->ranges->next) &&   /*   but only one */
00904              (indexnode->ranges->high ==            /*   & high==low */
00905               indexnode->ranges->low)))
00906             type |= ASN_PRIVATE;
00907         
00908         DEBUGMSGTL(("table_set_add_table",
00909                     "adding default index of type %d\n", type));
00910         netsnmp_table_dataset_add_index(table_set, type);
00911     }
00912 }
00914 void
00915 netsnmp_config_parse_table_set(const char *token, char *line)
00916 {
00917     oid             table_name[MAX_OID_LEN];
00918     size_t          table_name_length = MAX_OID_LEN;
00919     struct tree    *tp;
00920     netsnmp_table_data_set *table_set;
00921     data_set_tables *tables;
00922     unsigned int    mincol = 0xffffff, maxcol = 0;
00923     char           *pos;
00924 
00925     /*
00926      * instatiate a fake table based on MIB information 
00927      */
00928     DEBUGMSGTL(("9:table_set_add_table", "processing '%s'\n", line));
00929     if (NULL != (pos = strchr(line,' '))) {
00930         config_pwarn("ignoring extra tokens on line");
00931         snmp_log(LOG_WARNING,"  ignoring '%s'\n", pos);
00932         *pos = '\0';
00933     }
00934 
00935     /*
00936      * check for duplicate table
00937      */
00938     tables = (data_set_tables *) netsnmp_get_list_data(auto_tables, line);
00939     if (NULL != tables) {
00940         config_pwarn("duplicate table definition");
00941         return;
00942     }
00943 
00944     /*
00945      * parse oid and find tree structure
00946      */
00947     if (!snmp_parse_oid(line, table_name, &table_name_length)) {
00948         config_pwarn
00949             ("can't instatiate table since I can't parse the table name");
00950         return;
00951     }
00952     if(NULL == (tp = get_tree(table_name, table_name_length,
00953                               get_tree_head()))) {
00954         config_pwarn("can't instatiate table since "
00955                      "I can't find mib information about it");
00956         return;
00957     }
00958 
00959     if (NULL == (tp = tp->child_list) || NULL == tp->child_list) {
00960         config_pwarn("can't instatiate table since it doesn't appear to be "
00961                      "a proper table (no children)");
00962         return;
00963     }
00964 
00965     table_set = netsnmp_create_table_data_set(line);
00966 
00967     /*
00968      * check for augments indexes
00969      */
00970     if (NULL != tp->augments) {
00971         oid             name[MAX_OID_LEN];
00972         size_t          name_length = MAX_OID_LEN;
00973         struct tree    *tp2;
00974     
00975         if (!snmp_parse_oid(tp->augments, name, &name_length)) {
00976             config_pwarn("I can't parse the augment tabel name");
00977             snmp_log(LOG_WARNING, "  can't parse %s\n", tp->augments);
00978             return;
00979         }
00980         if(NULL == (tp2 = get_tree(name, name_length, get_tree_head()))) {
00981             config_pwarn("can't instatiate table since "
00982                          "I can't find mib information about augment table");
00983             snmp_log(LOG_WARNING, "  table %s not found in tree\n",
00984                      tp->augments);
00985             return;
00986         }
00987         _table_set_add_indexes(table_set, tp2);
00988     }
00989 
00990     _table_set_add_indexes(table_set, tp);
00991     
00992     /*
00993      * loop through children and add each column info 
00994      */
00995     for (tp = tp->child_list; tp; tp = tp->next_peer) {
00996         int             canwrite = 0;
00997         u_char          type;
00998         type = mib_to_asn_type(tp->type);
00999         if (type == (u_char) - 1) {
01000             config_pwarn("unknown column type");
01001             return;             /* xxx mem leak */
01002         }
01003 
01004         DEBUGMSGTL(("table_set_add_table",
01005                     "adding column %s(%d) of type %d (access %d)\n",
01006                     tp->label, tp->subid, type, tp->access));
01007 
01008         switch (tp->access) {
01009         case MIB_ACCESS_CREATE:
01010             table_set->allow_creation = 1;
01011         case MIB_ACCESS_READWRITE:
01012         case MIB_ACCESS_WRITEONLY:
01013             canwrite = 1;
01014         case MIB_ACCESS_READONLY:
01015             DEBUGMSGTL(("table_set_add_table",
01016                         "adding column %d of type %d\n", tp->subid, type));
01017             netsnmp_table_set_add_default_row(table_set, tp->subid, type,
01018                                               canwrite, NULL, 0);
01019             mincol = SNMP_MIN(mincol, tp->subid);
01020             maxcol = SNMP_MAX(maxcol, tp->subid);
01021             break;
01022 
01023         case MIB_ACCESS_NOACCESS:
01024         case MIB_ACCESS_NOTIFY:
01025             break;
01026 
01027         default:
01028             config_pwarn("unknown column access type");
01029             break;
01030         }
01031     }
01032 
01033     /*
01034      * register the table 
01035      */
01036     netsnmp_register_table_data_set(netsnmp_create_handler_registration
01037                                     (line, NULL, table_name,
01038                                      table_name_length,
01039                                      HANDLER_CAN_RWRITE), table_set, NULL);
01040 
01041     netsnmp_register_auto_data_table(table_set, NULL);
01042 }
01043 #endif /* DISABLE_MIB_LOADING */
01044 
01046 void
01047 netsnmp_config_parse_add_row(const char *token, char *line)
01048 {
01049     char            buf[SNMP_MAXBUF_MEDIUM];
01050     char            tname[SNMP_MAXBUF_MEDIUM];
01051     size_t          buf_size;
01052     int             rc;
01053 
01054     data_set_tables *tables;
01055     netsnmp_variable_list *vb;  /* containing only types */
01056     netsnmp_table_row *row;
01057     netsnmp_table_data_set_storage *dr;
01058 
01059     line = copy_nword(line, tname, SNMP_MAXBUF_MEDIUM);
01060 
01061     tables = (data_set_tables *) netsnmp_get_list_data(auto_tables, tname);
01062     if (!tables) {
01063         config_pwarn("Unknown table trying to add a row");
01064         return;
01065     }
01066 
01067     /*
01068      * do the indexes first 
01069      */
01070     row = netsnmp_create_table_data_row();
01071 
01072     for (vb = tables->table_set->table->indexes_template; vb;
01073          vb = vb->next_variable) {
01074         if (!line) {
01075             config_pwarn("missing an index value");
01076             return;
01077         }
01078 
01079         DEBUGMSGTL(("table_set_add_row", "adding index of type %d\n",
01080                     vb->type));
01081         buf_size = SNMP_MAXBUF_MEDIUM;
01082         line = read_config_read_memory(vb->type, line, buf, &buf_size);
01083         netsnmp_table_row_add_index(row, vb->type, buf, buf_size);
01084     }
01085 
01086     /*
01087      * then do the data 
01088      */
01089     for (dr = tables->table_set->default_row; dr; dr = dr->next) {
01090         if (!line) {
01091             config_pwarn("missing a data value. "
01092                          "All columns must be specified.");
01093             snmp_log(LOG_WARNING,"  can't find value for column %d\n",
01094                      dr->column - 1);
01095             return;
01096         }
01097 
01098         buf_size = SNMP_MAXBUF_MEDIUM;
01099         line = read_config_read_memory(dr->type, line, buf, &buf_size);
01100         DEBUGMSGTL(("table_set_add_row",
01101                     "adding data at column %d of type %d\n", dr->column,
01102                     dr->type));
01103         netsnmp_set_row_column(row, dr->column, dr->type, buf, buf_size);
01104         if (dr->writable)
01105             netsnmp_mark_row_column_writable(row, dr->column, 1);       /* make writable */
01106     }
01107     rc = netsnmp_table_data_add_row(tables->table_set->table, row);
01108     if (SNMPERR_SUCCESS != rc) {
01109         config_pwarn("error adding table row");
01110     }
01111     if (NULL != line) {
01112         config_pwarn("extra data value. Too many columns specified.");
01113         snmp_log(LOG_WARNING,"  extra data '%s'\n", line);
01114     }
01115 }
01116 
01117 
01118 /* ==================================
01119  *
01120  * Data Set API: Row operations
01121  *
01122  * ================================== */
01123 
01125 netsnmp_table_row *
01126 netsnmp_table_data_set_get_first_row(netsnmp_table_data_set *table)
01127 {
01128     return netsnmp_table_data_get_first_row(table->table);
01129 }
01130 
01132 netsnmp_table_row *
01133 netsnmp_table_data_set_get_next_row(netsnmp_table_data_set *table,
01134                                     netsnmp_table_row      *row)
01135 {
01136     return netsnmp_table_data_get_next_row(table->table, row);
01137 }
01138 
01139 int
01140 netsnmp_table_set_num_rows(netsnmp_table_data_set *table)
01141 {
01142     if (!table)
01143         return 0;
01144     return netsnmp_table_data_num_rows(table->table);
01145 }
01146 
01147 /* ==================================
01148  *
01149  * Data Set API: Column operations
01150  *
01151  * ================================== */
01152 
01156 netsnmp_table_data_set_storage *
01157 netsnmp_table_data_set_find_column(netsnmp_table_data_set_storage *start,
01158                                    unsigned int column)
01159 {
01160     while (start && start->column != column)
01161         start = start->next;
01162     return start;
01163 }
01164 
01168 int
01169 netsnmp_mark_row_column_writable(netsnmp_table_row *row, int column,
01170                                  int writable)
01171 {
01172     netsnmp_table_data_set_storage *data;
01173 
01174     if (!row)
01175         return SNMPERR_GENERR;
01176 
01177     data = (netsnmp_table_data_set_storage *) row->data;
01178     data = netsnmp_table_data_set_find_column(data, column);
01179 
01180     if (!data) {
01181         /*
01182          * create it 
01183          */
01184         data = SNMP_MALLOC_TYPEDEF(netsnmp_table_data_set_storage);
01185         if (!data) {
01186             snmp_log(LOG_CRIT, "no memory in netsnmp_set_row_column");
01187             return SNMPERR_MALLOC;
01188         }
01189         data->column = column;
01190         data->writable = writable;
01191         data->next = row->data;
01192         row->data = data;
01193     } else {
01194         data->writable = writable;
01195     }
01196     return SNMPERR_SUCCESS;
01197 }
01198 
01203 int
01204 netsnmp_set_row_column(netsnmp_table_row *row, unsigned int column,
01205                        int type, const char *value, size_t value_len)
01206 {
01207     netsnmp_table_data_set_storage *data;
01208 
01209     if (!row)
01210         return SNMPERR_GENERR;
01211 
01212     data = (netsnmp_table_data_set_storage *) row->data;
01213     data = netsnmp_table_data_set_find_column(data, column);
01214 
01215     if (!data) {
01216         /*
01217          * create it 
01218          */
01219         data = SNMP_MALLOC_TYPEDEF(netsnmp_table_data_set_storage);
01220         if (!data) {
01221             snmp_log(LOG_CRIT, "no memory in netsnmp_set_row_column");
01222             return SNMPERR_MALLOC;
01223         }
01224 
01225         data->column = column;
01226         data->type = type;
01227         data->next = row->data;
01228         row->data = data;
01229     }
01230 
01231     if (value) {
01232         if (data->type != type)
01233             return SNMPERR_GENERR;
01234 
01235         SNMP_FREE(data->data.voidp);
01236         if (value_len) {
01237             if (memdup(&data->data.string, value, (value_len)) !=
01238                 SNMPERR_SUCCESS) {
01239                 snmp_log(LOG_CRIT, "no memory in netsnmp_set_row_column");
01240                 return SNMPERR_MALLOC;
01241             }
01242         } else {
01243             data->data.string = malloc(1);
01244         }
01245         data->data_len = value_len;
01246     }
01247     return SNMPERR_SUCCESS;
01248 }
01249 
01250 /* ==================================
01251  *
01252  * Data Set API: Index operations
01253  *
01254  * ================================== */
01255 
01257 NETSNMP_INLINE void
01258 netsnmp_table_dataset_add_index(netsnmp_table_data_set *table, u_char type)
01259 {
01260     if (!table)
01261         return;
01262     netsnmp_table_data_add_index(table->table, type);
01263 }
01264 
01267 void
01268 #if HAVE_STDARG_H
01269 netsnmp_table_set_add_indexes(netsnmp_table_data_set *tset,
01270                               ...)
01271 #else
01272 netsnmp_table_set_add_indexes(va_alist)
01273      va_dcl
01274 #endif
01275 {
01276     va_list         debugargs;
01277     int             type;
01278 
01279 #if HAVE_STDARG_H
01280     va_start(debugargs, tset);
01281 #else
01282     netsnmp_table_data_set *tset;
01283 
01284     va_start(debugargs);
01285     tset = va_arg(debugargs, netsnmp_table_data_set *);
01286 #endif
01287 
01288     while ((type = va_arg(debugargs, int)) != 0) {
01289         netsnmp_table_dataset_add_index(tset, (u_char)type);
01290     }
01291 
01292     va_end(debugargs);
01293 }
01294 

net-snmpに対してSat Sep 5 13:14:27 2009に生成されました。  doxygen 1.4.7