net-snmp 5.7
oid_stash.c
00001 #include <net-snmp/net-snmp-config.h>
00002 
00003 #include <string.h>
00004 
00005 #include <stdlib.h>
00006 #include <sys/types.h>
00007 
00008 #include <net-snmp/net-snmp-features.h>
00009 #include <net-snmp/net-snmp-includes.h>
00010 
00011 netsnmp_feature_child_of(oid_stash_all, libnetsnmp)
00012 netsnmp_feature_child_of(oid_stash, oid_stash_all)
00013 netsnmp_feature_child_of(oid_stash_no_free, oid_stash_all)
00014 
00015 #ifndef NETSNMP_FEATURE_REMOVE_OID_STASH
00016 
00025 /*
00026  * xxx-rks: when you have some spare time:
00027  *
00028  * b) basically, everything currently creates one node per sub-oid,
00029  *    which is less than optimal. add code to create nodes with the
00030  *    longest possible OID per node, and split nodes when necessary
00031  *    during adds.
00032  *
00033  * c) If you are feeling really ambitious, also merge split nodes if
00034  *    possible on a delete.
00035  *
00036  * xxx-wes: uh, right, like I *ever* have that much time.
00037  *
00038  */
00039 
00040 /***************************************************************************
00041  *
00042  *
00043  ***************************************************************************/
00044 
00052 netsnmp_oid_stash_node *
00053 netsnmp_oid_stash_create_sized_node(size_t mysize)
00054 {
00055     netsnmp_oid_stash_node *ret;
00056     ret = SNMP_MALLOC_TYPEDEF(netsnmp_oid_stash_node);
00057     if (!ret)
00058         return NULL;
00059     ret->children = (netsnmp_oid_stash_node**) calloc(mysize, sizeof(netsnmp_oid_stash_node *));
00060     if (!ret->children) {
00061         free(ret);
00062         return NULL;
00063     }
00064     ret->children_size = mysize;
00065     return ret;
00066 }
00067 
00072 NETSNMP_INLINE netsnmp_oid_stash_node *
00073 netsnmp_oid_stash_create_node(void)
00074 {
00075     return netsnmp_oid_stash_create_sized_node(OID_STASH_CHILDREN_SIZE);
00076 }
00077 
00078 netsnmp_feature_child_of(oid_stash_add_data, oid_stash_all)
00079 #ifndef NETSNMP_FEATURE_REMOVE_OID_STASH_ADD_DATA
00080 
00091 int
00092 netsnmp_oid_stash_add_data(netsnmp_oid_stash_node **root,
00093                            const oid * lookup, size_t lookup_len, void *mydata)
00094 {
00095     netsnmp_oid_stash_node *curnode, *tmpp, *loopp;
00096     unsigned int    i;
00097 
00098     if (!root || !lookup || lookup_len == 0)
00099         return SNMPERR_GENERR;
00100 
00101     if (!*root) {
00102         *root = netsnmp_oid_stash_create_node();
00103         if (!*root)
00104             return SNMPERR_MALLOC;
00105     }
00106     DEBUGMSGTL(( "oid_stash", "stash_add_data "));
00107     DEBUGMSGOID(("oid_stash", lookup, lookup_len));
00108     DEBUGMSG((   "oid_stash", "\n"));
00109     tmpp = NULL;
00110     for (curnode = *root, i = 0; i < lookup_len; i++) {
00111         tmpp = curnode->children[lookup[i] % curnode->children_size];
00112         if (!tmpp) {
00113             /*
00114              * no child in array at all 
00115              */
00116             tmpp = curnode->children[lookup[i] % curnode->children_size] =
00117                 netsnmp_oid_stash_create_node();
00118             tmpp->value = lookup[i];
00119             tmpp->parent = curnode;
00120         } else {
00121             for (loopp = tmpp; loopp; loopp = loopp->next_sibling) {
00122                 if (loopp->value == lookup[i])
00123                     break;
00124             }
00125             if (loopp) {
00126                 tmpp = loopp;
00127             } else {
00128                 /*
00129                  * none exists.  Create it 
00130                  */
00131                 loopp = netsnmp_oid_stash_create_node();
00132                 loopp->value = lookup[i];
00133                 loopp->next_sibling = tmpp;
00134                 loopp->parent = curnode;
00135                 tmpp->prev_sibling = loopp;
00136                 curnode->children[lookup[i] % curnode->children_size] =
00137                     loopp;
00138                 tmpp = loopp;
00139             }
00140             /*
00141              * tmpp now points to the proper node 
00142              */
00143         }
00144         curnode = tmpp;
00145     }
00146     /*
00147      * tmpp now points to the exact match 
00148      */
00149     if (curnode->thedata)
00150         return SNMPERR_GENERR;
00151     if (NULL == tmpp)
00152         return SNMPERR_GENERR;
00153     tmpp->thedata = mydata;
00154     return SNMPERR_SUCCESS;
00155 }
00156 #endif /* NETSNMP_FEATURE_REMOVE_OID_STASH_ADD_DATA */
00157 
00163 netsnmp_oid_stash_node *
00164 netsnmp_oid_stash_get_node(netsnmp_oid_stash_node *root,
00165                            const oid * lookup, size_t lookup_len)
00166 {
00167     netsnmp_oid_stash_node *curnode, *tmpp, *loopp;
00168     unsigned int    i;
00169 
00170     if (!root)
00171         return NULL;
00172     tmpp = NULL;
00173     for (curnode = root, i = 0; i < lookup_len; i++) {
00174         tmpp = curnode->children[lookup[i] % curnode->children_size];
00175         if (!tmpp) {
00176             return NULL;
00177         } else {
00178             for (loopp = tmpp; loopp; loopp = loopp->next_sibling) {
00179                 if (loopp->value == lookup[i])
00180                     break;
00181             }
00182             if (loopp) {
00183                 tmpp = loopp;
00184             } else {
00185                 return NULL;
00186             }
00187         }
00188         curnode = tmpp;
00189     }
00190     return tmpp;
00191 }
00192 
00200 netsnmp_feature_child_of(oid_stash_iterate, oid_stash_all)
00201 #ifndef NETSNMP_FEATURE_REMOVE_OID_STASH_ITERATE
00202 netsnmp_oid_stash_node *
00203 netsnmp_oid_stash_getnext_node(netsnmp_oid_stash_node *root,
00204                                oid * lookup, size_t lookup_len)
00205 {
00206     netsnmp_oid_stash_node *curnode, *tmpp, *loopp;
00207     unsigned int    i, j, bigger_than = 0, do_bigger = 0;
00208 
00209     if (!root)
00210         return NULL;
00211     tmpp = NULL;
00212 
00213     /* get closest matching node */
00214     for (curnode = root, i = 0; i < lookup_len; i++) {
00215         tmpp = curnode->children[lookup[i] % curnode->children_size];
00216         if (!tmpp) {
00217             break;
00218         } else {
00219             for (loopp = tmpp; loopp; loopp = loopp->next_sibling) {
00220                 if (loopp->value == lookup[i])
00221                     break;
00222             }
00223             if (loopp) {
00224                 tmpp = loopp;
00225             } else {
00226                 break;
00227             }
00228         }
00229         curnode = tmpp;
00230     }
00231 
00232     /* find the *next* node lexographically greater */
00233     if (!curnode)
00234         return NULL; /* ack! */
00235 
00236     if (i+1 < lookup_len) {
00237         bigger_than = lookup[i+1];
00238         do_bigger = 1;
00239     }
00240 
00241     do {
00242         /* check the children first */
00243         tmpp = NULL;
00244         /* next child must be (next) greater than our next search node */
00245         /* XXX: should start this loop at best_nums[i]%... and wrap */
00246         for(j = 0; j < curnode->children_size; j++) {
00247             for (loopp = curnode->children[j];
00248                  loopp; loopp = loopp->next_sibling) {
00249                 if ((!do_bigger || loopp->value > bigger_than) &&
00250                     (!tmpp || tmpp->value > loopp->value)) {
00251                     tmpp = loopp;
00252                     /* XXX: can do better and include min_nums[i] */
00253                     if (tmpp->value <= curnode->children_size-1) {
00254                         /* best we can do. */
00255                         goto done_this_loop;
00256                     }
00257                 }
00258             }
00259         }
00260 
00261       done_this_loop:
00262         if (tmpp && tmpp->thedata)
00263             /* found a node with data.  Go with it. */
00264             return tmpp;
00265 
00266         if (tmpp) {
00267             /* found a child node without data, maybe find a grandchild? */
00268             do_bigger = 0;
00269             curnode = tmpp;
00270         } else {
00271             /* no respectable children (the bums), we'll have to go up.
00272                But to do so, they must be better than our current best_num + 1.
00273             */
00274             do_bigger = 1;
00275             bigger_than = curnode->value;
00276             curnode = curnode->parent;
00277         }
00278     } while (curnode);
00279 
00280     /* fell off the top */
00281     return NULL;
00282 }
00283 #endif /* NETSNMP_FEATURE_REMOVE_OID_STASH_ITERATE */
00284 
00285 netsnmp_feature_child_of(oid_stash_get_data, oid_stash_all)
00286 #ifndef NETSNMP_FEATURE_REMOVE_OID_STASH_GET_DATA
00287 
00296 void           *
00297 netsnmp_oid_stash_get_data(netsnmp_oid_stash_node *root,
00298                            const oid * lookup, size_t lookup_len)
00299 {
00300     netsnmp_oid_stash_node *ret;
00301     ret = netsnmp_oid_stash_get_node(root, lookup, lookup_len);
00302     if (ret)
00303         return ret->thedata;
00304     return NULL;
00305 }
00306 #endif /* NETSNMP_FEATURE_REMOVE_OID_STASH_GET_DATA */
00307 
00319 netsnmp_feature_child_of(oid_stash_store_all, oid_stash_all)
00320 #ifndef NETSNMP_FEATURE_REMOVE_OID_STASH_STORE_ALL
00321 int
00322 netsnmp_oid_stash_store_all(int majorID, int minorID,
00323                             void *serverarg, void *clientarg) {
00324     oid oidbase[MAX_OID_LEN];
00325     netsnmp_oid_stash_save_info *sinfo;
00326     
00327     if (!clientarg)
00328         return SNMP_ERR_NOERROR;
00329     
00330     sinfo = (netsnmp_oid_stash_save_info *) clientarg;
00331     netsnmp_oid_stash_store(*(sinfo->root), sinfo->token, sinfo->dumpfn,
00332                             oidbase,0);
00333     return SNMP_ERR_NOERROR;
00334 }
00335 #endif /* NETSNMP_FEATURE_REMOVE_OID_STASH_STORE_ALL */
00336 
00352 void
00353 netsnmp_oid_stash_store(netsnmp_oid_stash_node *root,
00354                         const char *tokenname, NetSNMPStashDump *dumpfn,
00355                         oid *curoid, size_t curoid_len) {
00356 
00357     char buf[SNMP_MAXBUF];
00358     netsnmp_oid_stash_node *tmpp;
00359     char *cp;
00360     char *appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
00361                                           NETSNMP_DS_LIB_APPTYPE);
00362     int i;
00363     
00364     if (!tokenname || !root || !curoid || !dumpfn)
00365         return;
00366 
00367     for (i = 0; i < (int)root->children_size; i++) {
00368         if (root->children[i]) {
00369             for (tmpp = root->children[i]; tmpp; tmpp = tmpp->next_sibling) {
00370                 curoid[curoid_len] = tmpp->value;
00371                 if (tmpp->thedata) {
00372                     snprintf(buf, sizeof(buf), "%s ", tokenname);
00373                     cp = read_config_save_objid(buf+strlen(buf), curoid,
00374                                                 curoid_len+1);
00375                     *cp++ = ' ';
00376                     *cp = '\0';
00377                     if ((*dumpfn)(cp, sizeof(buf) - strlen(buf),
00378                                   tmpp->thedata, tmpp))
00379                         read_config_store(appname, buf);
00380                 }
00381                 netsnmp_oid_stash_store(tmpp, tokenname, dumpfn,
00382                                         curoid, curoid_len+1);
00383             }
00384         }
00385     }
00386 }
00387 
00392 void 
00393 oid_stash_dump(netsnmp_oid_stash_node *root, char *prefix)
00394 {
00395     char            myprefix[MAX_OID_LEN * 4];
00396     netsnmp_oid_stash_node *tmpp;
00397     int             prefix_len = strlen(prefix) + 1;    /* actually it's +2 */
00398     unsigned int    i;
00399 
00400     memset(myprefix, ' ', MAX_OID_LEN * 4);
00401     myprefix[prefix_len] = '\0';
00402 
00403     for (i = 0; i < root->children_size; i++) {
00404         if (root->children[i]) {
00405             for (tmpp = root->children[i]; tmpp; tmpp = tmpp->next_sibling) {
00406                 printf("%s%" NETSNMP_PRIo "d@%d: %s\n", prefix, tmpp->value, i,
00407                        (tmpp->thedata) ? "DATA" : "");
00408                 oid_stash_dump(tmpp, myprefix);
00409             }
00410         }
00411     }
00412 }
00413 
00419 void
00420 netsnmp_oid_stash_free(netsnmp_oid_stash_node **root,
00421                        NetSNMPStashFreeNode *freefn) {
00422 
00423     netsnmp_oid_stash_node *curnode, *tmpp;
00424     unsigned int    i;
00425 
00426     if (!root || !*root)
00427         return;
00428 
00429     /* loop through all our children and free each node */
00430     for (i = 0; i < (*root)->children_size; i++) {
00431         if ((*root)->children[i]) {
00432             for(tmpp = (*root)->children[i]; tmpp; tmpp = curnode) {
00433                 if (tmpp->thedata) {
00434                     if (freefn)
00435                         (*freefn)(tmpp->thedata);
00436                     else
00437                         free(tmpp->thedata);
00438                 }
00439                 curnode = tmpp->next_sibling;
00440                 netsnmp_oid_stash_free(&tmpp, freefn);
00441             }
00442         }
00443     }
00444     free((*root)->children);
00445     free (*root);
00446     *root = NULL;
00447 }
00448 
00449 #else /* NETSNMP_FEATURE_REMOVE_OID_STASH */
00450 netsnmp_feature_unused(oid_stash);
00451 #endif/* NETSNMP_FEATURE_REMOVE_OID_STASH */
00452 
00453 #ifndef NETSNMP_FEATURE_REMOVE_OID_STASH_NO_FREE
00454 void
00455 netsnmp_oid_stash_no_free(void *bogus)
00456 {
00457     /* noop */
00458 }
00459 #endif /* NETSNMP_FEATURE_REMOVE_OID_STASH_NO_FREE */
00460