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
1.3.9.1
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.