Logo
Home page Net-SNMP

Archive Search:

Require all words?

Site Search:
Google
Main Page | Modules | Data Structures | File List | Data Fields | Related Pages | Examples

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

Generated on Fri Dec 30 13:47:51 2005 for net-snmp by  doxygen 1.3.9.1

Valid CSS!


Last modified: Thursday, 01-Mar-2007 16:20:13 PST
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.