net-snmp 5.7
snmp_enum.c
00001 #include <net-snmp/net-snmp-config.h>
00002 #include <net-snmp/net-snmp-features.h>
00003 
00004 #ifdef HAVE_STDLIB_H
00005 #include <stdlib.h>
00006 #endif
00007 #include <stdio.h>
00008 #if HAVE_STRING_H
00009 #include <string.h>
00010 #else
00011 #include <strings.h>
00012 #endif
00013 
00014 #if HAVE_DMALLOC_H
00015 #include <dmalloc.h>
00016 #endif
00017 #include <sys/types.h>
00018 
00019 #include <net-snmp/types.h>
00020 #include <net-snmp/config_api.h>
00021 
00022 #include <net-snmp/library/snmp_enum.h>
00023 #include <net-snmp/library/tools.h>
00024 #include <net-snmp/library/snmp_assert.h>
00025 
00026 netsnmp_feature_child_of(snmp_enum_all, libnetsnmp)
00027 
00028 netsnmp_feature_child_of(se_find_free_value_in_slist, snmp_enum_all)
00029 netsnmp_feature_child_of(snmp_enum_store_list, snmp_enum_all)
00030 netsnmp_feature_child_of(snmp_enum_store_slist, snmp_enum_all)
00031 netsnmp_feature_child_of(snmp_enum_clear, snmp_enum_all)
00032 
00033 struct snmp_enum_list_str {
00034     char           *name;
00035     struct snmp_enum_list *list;
00036     struct snmp_enum_list_str *next;
00037 };
00038 
00039 static struct snmp_enum_list ***snmp_enum_lists;
00040 unsigned int    current_maj_num;
00041 unsigned int    current_min_num;
00042 static struct snmp_enum_list_str *sliststorage;
00043 
00044 static void
00045 free_enum_list(struct snmp_enum_list *list);
00046 
00047 int
00048 init_snmp_enum(const char *type)
00049 {
00050     int             i;
00051 
00052     if (NULL != snmp_enum_lists)
00053         return SE_OK;
00054 
00055     snmp_enum_lists = (struct snmp_enum_list ***)
00056         calloc(1, sizeof(struct snmp_enum_list **) * SE_MAX_IDS);
00057     if (!snmp_enum_lists)
00058         return SE_NOMEM;
00059     current_maj_num = SE_MAX_IDS;
00060 
00061     for (i = 0; i < SE_MAX_IDS; i++) {
00062         if (!snmp_enum_lists[i])
00063             snmp_enum_lists[i] = (struct snmp_enum_list **)
00064                 calloc(1, sizeof(struct snmp_enum_list *) * SE_MAX_SUBIDS);
00065         if (!snmp_enum_lists[i])
00066             return SE_NOMEM;
00067     }
00068     current_min_num = SE_MAX_SUBIDS;
00069 
00070     register_config_handler(type, "enum", se_read_conf, NULL, NULL);
00071     return SE_OK;
00072 }
00073 
00074 int
00075 se_store_in_list(struct snmp_enum_list *new_list,
00076               unsigned int major, unsigned int minor)
00077 {
00078     int             ret = SE_OK;
00079 
00080     if (major > current_maj_num || minor > current_min_num) {
00081         /*
00082          * XXX: realloc 
00083          */
00084         return SE_NOMEM;
00085     }
00086     netsnmp_assert(NULL != snmp_enum_lists);
00087 
00088     if (snmp_enum_lists[major][minor] != NULL)
00089         ret = SE_ALREADY_THERE;
00090 
00091     snmp_enum_lists[major][minor] = new_list;
00092 
00093     return ret;
00094 }
00095 
00096 void
00097 se_read_conf(const char *word, char *cptr)
00098 {
00099     int major, minor;
00100     int value;
00101     char *cp, *cp2;
00102     char e_name[BUFSIZ];
00103     char e_enum[  BUFSIZ];
00104 
00105     if (!cptr || *cptr=='\0')
00106         return;
00107 
00108     /*
00109      * Extract the first token
00110      *   (which should be the name of the list)
00111      */
00112     cp = copy_nword(cptr, e_name, sizeof(e_name));
00113     cp = skip_white(cp);
00114     if (!cp || *cp=='\0')
00115         return;
00116 
00117 
00118     /*
00119      * Add each remaining enumeration to the list,
00120      *   using the appropriate style interface
00121      */
00122     if (sscanf(e_name, "%d:%d", &major, &minor) == 2) {
00123         /*
00124          *  Numeric major/minor style
00125          */
00126         while (1) {
00127             cp = copy_nword(cp, e_enum, sizeof(e_enum));
00128             if (sscanf(e_enum, "%d:", &value) != 1) {
00129                 break;
00130             }
00131             cp2 = e_enum;
00132             while (*(cp2++) != ':')
00133                 ;
00134             se_add_pair(major, minor, strdup(cp2), value);
00135             if (!cp)
00136                 break;
00137         }
00138     } else {
00139         /*
00140          *  Named enumeration
00141          */
00142         while (1) {
00143             cp = copy_nword(cp, e_enum, sizeof(e_enum));
00144             if (sscanf(e_enum, "%d:", &value) != 1) {
00145                 break;
00146             }
00147             cp2 = e_enum;
00148             while (*(cp2++) != ':')
00149                 ;
00150             se_add_pair_to_slist(e_name, strdup(cp2), value);
00151             if (!cp)
00152                 break;
00153         }
00154     }
00155 }
00156 
00157 void
00158 se_store_enum_list(struct snmp_enum_list *new_list,
00159                    const char *token, char *type)
00160 {
00161     struct snmp_enum_list *listp = new_list;
00162     char line[2048];
00163     char buf[512];
00164     int  len = 0;
00165 
00166     snprintf(line, sizeof(line), "enum %s", token);
00167     while (listp) {
00168         snprintf(buf, sizeof(buf), " %d:%s", listp->value, listp->label);
00169         /*
00170          * Calculate the space left in the buffer.
00171          * If this is not sufficient to include the next enum,
00172          *   then save the line so far, and start again.
00173          */
00174         len = sizeof(line) - strlen(line);
00175         if ((int)strlen(buf) > len) {
00176             read_config_store(type, line);
00177             snprintf(line, sizeof(line), "enum %s", token);
00178             len = sizeof(line);
00179         }
00180 
00181         strncat(line, buf, len);
00182         listp = listp->next;
00183     }
00184 
00185     /*
00186      * If there's anything left, then save that.
00187      * But don't bother saving an empty 'overflow' line.
00188      */
00189     if (len != sizeof(line))
00190         read_config_store(type, line);
00191 
00192     return;
00193 }
00194 
00195 #ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST
00196 void
00197 se_store_list(unsigned int major, unsigned int minor, char *type)
00198 {
00199     char token[32];
00200 
00201     snprintf(token, sizeof(token), "%d:%d", major, minor);
00202     se_store_enum_list(se_find_list(major, minor), token, type);
00203 }
00204 #endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST */
00205 
00206 struct snmp_enum_list *
00207 se_find_list(unsigned int major, unsigned int minor)
00208 {
00209     if (major > current_maj_num || minor > current_min_num)
00210         return NULL;
00211     netsnmp_assert(NULL != snmp_enum_lists);
00212 
00213     return snmp_enum_lists[major][minor];
00214 }
00215 
00216 int
00217 se_find_value_in_list(struct snmp_enum_list *list, const char *label)
00218 {
00219     if (!list)
00220         return SE_DNE;          /* XXX: um, no good solution here */
00221     while (list) {
00222         if (strcmp(list->label, label) == 0)
00223             return (list->value);
00224         list = list->next;
00225     }
00226 
00227     return SE_DNE;              /* XXX: um, no good solution here */
00228 }
00229 
00230 int
00231 se_find_free_value_in_list(struct snmp_enum_list *list)
00232 {
00233     int max_value = 0;
00234     if (!list)
00235         return SE_DNE;
00236 
00237     for (;list; list=list->next) {
00238         if (max_value < list->value)
00239             max_value = list->value;
00240     }
00241     return max_value+1;
00242 }
00243 
00244 int
00245 se_find_value(unsigned int major, unsigned int minor, const char *label)
00246 {
00247     return se_find_value_in_list(se_find_list(major, minor), label);
00248 }
00249 
00250 int
00251 se_find_free_value(unsigned int major, unsigned int minor)
00252 {
00253     return se_find_free_value_in_list(se_find_list(major, minor));
00254 }
00255 
00256 char           *
00257 se_find_label_in_list(struct snmp_enum_list *list, int value)
00258 {
00259     if (!list)
00260         return NULL;
00261     while (list) {
00262         if (list->value == value)
00263             return (list->label);
00264         list = list->next;
00265     }
00266     return NULL;
00267 }
00268 
00269 char           *
00270 se_find_label(unsigned int major, unsigned int minor, int value)
00271 {
00272     return se_find_label_in_list(se_find_list(major, minor), value);
00273 }
00274 
00275 int
00276 se_add_pair_to_list(struct snmp_enum_list **list, char *label, int value)
00277 {
00278     struct snmp_enum_list *lastnode = NULL, *tmp;
00279 
00280     if (!list)
00281         return SE_DNE;
00282 
00283     tmp = *list;
00284     while (tmp) {
00285         if (tmp->value == value) {
00286             free(label);
00287             return (SE_ALREADY_THERE);
00288         }
00289         lastnode = tmp;
00290         tmp = tmp->next;
00291     }
00292 
00293     if (lastnode) {
00294         lastnode->next = SNMP_MALLOC_STRUCT(snmp_enum_list);
00295         lastnode = lastnode->next;
00296     } else {
00297         (*list) = SNMP_MALLOC_STRUCT(snmp_enum_list);
00298         lastnode = (*list);
00299     }
00300     if (!lastnode)
00301         return (SE_NOMEM);
00302     lastnode->label = label;
00303     lastnode->value = value;
00304     lastnode->next = NULL;
00305     return (SE_OK);
00306 }
00307 
00308 int
00309 se_add_pair(unsigned int major, unsigned int minor, char *label, int value)
00310 {
00311     struct snmp_enum_list *list = se_find_list(major, minor);
00312     int             created = (list) ? 1 : 0;
00313     int             ret = se_add_pair_to_list(&list, label, value);
00314     if (!created)
00315         se_store_in_list(list, major, minor);
00316     return ret;
00317 }
00318 
00319 /*
00320  * remember a list of enums based on a lookup name.
00321  */
00322 static struct snmp_enum_list **
00323 se_find_slist_ptr(const char *listname)
00324 {
00325     struct snmp_enum_list_str *sptr, *lastp = NULL;
00326     if (!listname)
00327         return NULL;
00328 
00329     for (sptr = sliststorage;
00330          sptr != NULL; lastp = sptr, sptr = sptr->next)
00331         if (sptr->name && strcmp(sptr->name, listname) == 0)
00332             return &sptr->list;
00333 
00334     return NULL;
00335 }
00336 
00337 struct snmp_enum_list *
00338 se_find_slist(const char *listname)
00339 {
00340     struct snmp_enum_list **ptr = se_find_slist_ptr(listname);
00341     return ptr ? *ptr : NULL;
00342 }
00343 
00344 char           *
00345 se_find_label_in_slist(const char *listname, int value)
00346 {
00347     return (se_find_label_in_list(se_find_slist(listname), value));
00348 }
00349 
00350 int
00351 se_find_value_in_slist(const char *listname, const char *label)
00352 {
00353     return (se_find_value_in_list(se_find_slist(listname), label));
00354 }
00355 
00356 #ifndef NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST
00357 int
00358 se_find_free_value_in_slist(const char *listname)
00359 {
00360     return (se_find_free_value_in_list(se_find_slist(listname)));
00361 }
00362 #endif /* NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST */
00363 
00364 int
00365 se_add_pair_to_slist(const char *listname, char *label, int value)
00366 {
00367     struct snmp_enum_list *list = se_find_slist(listname);
00368     int             created = (list) ? 1 : 0;
00369     int             ret = se_add_pair_to_list(&list, label, value);
00370 
00371     if (!created) {
00372         struct snmp_enum_list_str *sptr =
00373             SNMP_MALLOC_STRUCT(snmp_enum_list_str);
00374         if (!sptr) {
00375             free_enum_list(list);
00376             return SE_NOMEM;
00377         }
00378         sptr->next = sliststorage;
00379         sptr->name = strdup(listname);
00380         sptr->list = list;
00381         sliststorage = sptr;
00382     }
00383     return ret;
00384 }
00385 
00386 static void
00387 free_enum_list(struct snmp_enum_list *list)
00388 {
00389     struct snmp_enum_list *next;
00390 
00391     while (list) {
00392         next = list->next;
00393         SNMP_FREE(list->label);
00394         SNMP_FREE(list);
00395         list = next;
00396     }
00397 }
00398 
00399 void
00400 clear_snmp_enum(void)
00401 {
00402     struct snmp_enum_list_str *sptr = sliststorage, *next = NULL;
00403     int i, j;
00404 
00405     while (sptr != NULL) {
00406         next = sptr->next;
00407         free_enum_list(sptr->list);
00408         SNMP_FREE(sptr->name);
00409         SNMP_FREE(sptr);
00410         sptr = next;
00411     }
00412     sliststorage = NULL;
00413 
00414     if (snmp_enum_lists) {
00415         for (i = 0; i < SE_MAX_IDS; i++) {
00416             if (snmp_enum_lists[i]) {
00417                 for (j = 0; j < SE_MAX_SUBIDS; j++) {
00418                     if (snmp_enum_lists[i][j])
00419                         free_enum_list(snmp_enum_lists[i][j]);
00420                 }
00421                 SNMP_FREE(snmp_enum_lists[i]);
00422             }
00423         }
00424         SNMP_FREE(snmp_enum_lists);
00425     }
00426 }
00427 
00428 void
00429 se_clear_list(struct snmp_enum_list **list)
00430 {
00431     struct snmp_enum_list *this_entry, *next_entry;
00432 
00433     if (!list)
00434         return;
00435 
00436     this_entry = *list;
00437     while (this_entry) {
00438         next_entry = this_entry->next;
00439         SNMP_FREE(this_entry->label);
00440         SNMP_FREE(this_entry);
00441         this_entry = next_entry;
00442     }
00443     *list = NULL;
00444     return;
00445 }
00446 
00447 #ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST
00448 void
00449 se_store_slist(const char *listname, char *type)
00450 {
00451     struct snmp_enum_list *list = se_find_slist(listname);
00452     se_store_enum_list(list, listname, type);
00453 }
00454 
00455 int
00456 se_store_slist_callback(int majorID, int minorID,
00457                         void *serverargs, void *clientargs)
00458 {
00459     char *appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
00460                                           NETSNMP_DS_LIB_APPTYPE);
00461     se_store_slist((char *)clientargs, appname);
00462     return SNMPERR_SUCCESS;
00463 }
00464 #endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST */
00465 
00466 #ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR
00467 void
00468 se_clear_slist(const char *listname)
00469 {
00470     se_clear_list(se_find_slist_ptr(listname));
00471 }
00472 
00473 void
00474 se_clear_all_lists(void)
00475 {
00476     struct snmp_enum_list_str *sptr = NULL;
00477 
00478     for (sptr = sliststorage; sptr != NULL; sptr = sptr->next)
00479         se_clear_list(&(sptr->list));
00480 }
00481 #endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR */