net-snmp 5.7
data_list.c
00001 /*
00002  * netsnmp_data_list.c
00003  *
00004  * $Id$
00005  */
00006 #include <net-snmp/net-snmp-config.h>
00007 #include <net-snmp/net-snmp-features.h>
00008 #include <net-snmp/net-snmp-includes.h>
00009 
00010 netsnmp_feature_child_of(data_list_all, libnetsnmp)
00011 
00012 netsnmp_feature_child_of(data_list_add_data, data_list_all)
00013 netsnmp_feature_child_of(data_list_get_list_node, data_list_all)
00014 
00024 NETSNMP_INLINE void
00025 netsnmp_free_list_data(netsnmp_data_list *node)
00026 {
00027     Netsnmp_Free_List_Data *beer;
00028     if (!node)
00029         return;
00030 
00031     beer = node->free_func;
00032     if (beer)
00033         (beer) (node->data);
00034     SNMP_FREE(node->name);
00035 }
00036 
00040 NETSNMP_INLINE void
00041 netsnmp_free_all_list_data(netsnmp_data_list *head)
00042 {
00043     netsnmp_data_list *tmpptr;
00044     for (; head;) {
00045         netsnmp_free_list_data(head);
00046         tmpptr = head;
00047         head = head->next;
00048         SNMP_FREE(tmpptr);
00049     }
00050 }
00051 
00058 NETSNMP_INLINE netsnmp_data_list *
00059 netsnmp_create_data_list(const char *name, void *data,
00060                          Netsnmp_Free_List_Data * beer)
00061 {
00062     netsnmp_data_list *node;
00063     
00064     if (!name)
00065         return NULL;
00066     node = SNMP_MALLOC_TYPEDEF(netsnmp_data_list);
00067     if (!node)
00068         return NULL;
00069     node->name = strdup(name);
00070     if (!node->name) {
00071         free(node);
00072         return NULL;
00073     }
00074     node->data = data;
00075     node->free_func = beer;
00076     return node;
00077 }
00078 
00083 NETSNMP_INLINE void
00084 netsnmp_data_list_add_node(netsnmp_data_list **head, netsnmp_data_list *node)
00085 {
00086     netsnmp_data_list *ptr;
00087 
00088     netsnmp_assert(NULL != head);
00089     netsnmp_assert(NULL != node);
00090     netsnmp_assert(NULL != node->name);
00091 
00092     DEBUGMSGTL(("data_list","adding key '%s'\n", node->name));
00093 
00094     if (!*head) {
00095         *head = node;
00096         return;
00097     }
00098 
00099     if (0 == strcmp(node->name, (*head)->name)) {
00100         netsnmp_assert(!"list key == is unique"); /* always fail */
00101         snmp_log(LOG_WARNING,
00102                  "WARNING: adding duplicate key '%s' to data list\n",
00103                  node->name);
00104     }
00105 
00106     for (ptr = *head; ptr->next != NULL; ptr = ptr->next) {
00107         netsnmp_assert(NULL != ptr->name);
00108         if (0 == strcmp(node->name, ptr->name)) {
00109             netsnmp_assert(!"list key == is unique"); /* always fail */
00110             snmp_log(LOG_WARNING,
00111                      "WARNING: adding duplicate key '%s' to data list\n",
00112                      node->name);
00113         }
00114     }
00115 
00116     netsnmp_assert(NULL != ptr);
00117     if (ptr)                    /* should always be true */
00118         ptr->next = node;
00119 }
00120 
00127 NETSNMP_INLINE void
00128 netsnmp_add_list_data(netsnmp_data_list **head, netsnmp_data_list *node)
00129 {
00130     netsnmp_data_list_add_node(head, node);
00131 }
00132 
00140 #ifndef NETSNMP_FEATURE_REMOVE_DATA_LIST_ADD_DATA
00141 NETSNMP_INLINE netsnmp_data_list *
00142 netsnmp_data_list_add_data(netsnmp_data_list **head, const char *name,
00143                            void *data, Netsnmp_Free_List_Data * beer)
00144 {
00145     netsnmp_data_list *node;
00146     if (!name) {
00147         snmp_log(LOG_ERR,"no name provided.");
00148         return NULL;
00149     }
00150     node = netsnmp_create_data_list(name, data, beer);
00151     if(NULL == node) {
00152         snmp_log(LOG_ERR,"could not allocate memory for node.");
00153         return NULL;
00154     }
00155     
00156     netsnmp_add_list_data(head, node);
00157 
00158     return node;
00159 }
00160 #endif /* NETSNMP_FEATURE_REMOVE_DATA_LIST_ADD_DATA */
00161 
00167 NETSNMP_INLINE void    *
00168 netsnmp_get_list_data(netsnmp_data_list *head, const char *name)
00169 {
00170     if (!name)
00171         return NULL;
00172     for (; head; head = head->next)
00173         if (head->name && strcmp(head->name, name) == 0)
00174             break;
00175     if (head)
00176         return head->data;
00177     return NULL;
00178 }
00179 
00185 #ifndef NETSNMP_FEATURE_REMOVE_DATA_LIST_GET_LIST_NODE
00186 NETSNMP_INLINE netsnmp_data_list    *
00187 netsnmp_get_list_node(netsnmp_data_list *head, const char *name)
00188 {
00189     if (!name)
00190         return NULL;
00191     for (; head; head = head->next)
00192         if (head->name && strcmp(head->name, name) == 0)
00193             break;
00194     if (head)
00195         return head;
00196     return NULL;
00197 }
00198 #endif /* NETSNMP_FEATURE_REMOVE_DATA_LIST_GET_LIST_NODE */
00199 
00205 int
00206 netsnmp_remove_list_node(netsnmp_data_list **realhead, const char *name)
00207 {
00208     netsnmp_data_list *head, *prev;
00209     if (!name)
00210         return 1;
00211     for (head = *realhead, prev = NULL; head;
00212          prev = head, head = head->next) {
00213         if (head->name && strcmp(head->name, name) == 0) {
00214             if (prev)
00215                 prev->next = head->next;
00216             else
00217                 *realhead = head->next;
00218             netsnmp_free_list_data(head);
00219             free(head);
00220             return 0;
00221         }
00222     }
00223     return 1;
00224 }
00225 
00227 static netsnmp_data_list *saveHead;
00228 
00238 void
00239 netsnmp_register_save_list(netsnmp_data_list **datalist,
00240                            const char *type, const char *token,
00241                            Netsnmp_Save_List_Data *data_list_save_ptr,
00242                            Netsnmp_Read_List_Data *data_list_read_ptr,
00243                            Netsnmp_Free_List_Data *data_list_free_ptr) {
00244     netsnmp_data_list_saveinfo *info =
00245         SNMP_MALLOC_TYPEDEF(netsnmp_data_list_saveinfo);
00246 
00247     if (!info) {
00248         snmp_log(LOG_ERR, "couldn't malloc a netsnmp_data_list_saveinfo typedef");
00249         return;
00250     }
00251 
00252     info->datalist = datalist;
00253     info->token = token;
00254     info->type = type;
00255     if (!info->type) {
00256         info->type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
00257                                            NETSNMP_DS_LIB_APPTYPE);
00258     }
00259 
00260     /* function which will save the data */
00261     info->data_list_save_ptr = data_list_save_ptr;
00262     if (data_list_save_ptr)
00263         snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
00264                                netsnmp_save_all_data_callback, info);
00265 
00266     /* function which will read the data back in */
00267     info->data_list_read_ptr = data_list_read_ptr;
00268     if (data_list_read_ptr) {
00270         netsnmp_add_list_data(&saveHead,
00271                               netsnmp_create_data_list(token, info, NULL));
00272         register_config_handler(type, token, netsnmp_read_data_callback,
00273                                 NULL /* XXX */, NULL);
00274     }
00275 
00276     info->data_list_free_ptr = data_list_free_ptr;
00277 }
00278 
00279 
00287 int
00288 netsnmp_save_all_data_callback(int major, int minor,
00289                                void *serverarg, void *clientarg) {
00290     netsnmp_data_list_saveinfo *info = (netsnmp_data_list_saveinfo *)clientarg;
00291 
00292     if (!clientarg) {
00293         snmp_log(LOG_WARNING, "netsnmp_save_all_data_callback called with no passed data");
00294         return SNMP_ERR_NOERROR;
00295     }
00296 
00297     netsnmp_save_all_data(*(info->datalist), info->type, info->token,
00298                           info->data_list_save_ptr);
00299     return SNMP_ERR_NOERROR;
00300 }    
00301 
00304 int
00305 netsnmp_save_all_data(netsnmp_data_list *head,
00306                       const char *type, const char *token,
00307                       Netsnmp_Save_List_Data * data_list_save_ptr)
00308 {
00309     char buf[SNMP_MAXBUF], *cp;
00310 
00311     for (; head; head = head->next) {
00312         if (head->name) {
00313             /* save begining of line */
00314             snprintf(buf, sizeof(buf), "%s ", token);
00315             cp = buf + strlen(buf);
00316             cp = read_config_save_octet_string(cp, (u_char*)head->name,
00317                                                strlen(head->name));
00318             *cp++ = ' ';
00319 
00320             /* call registered function to save the rest */
00321             if (!(data_list_save_ptr)(cp,
00322                                       sizeof(buf) - strlen(buf),
00323                                       head->data)) {
00324                 read_config_store(type, buf);
00325             }
00326         }
00327     }
00328     return SNMP_ERR_NOERROR;
00329 }
00330 
00340 void
00341 netsnmp_read_data_callback(const char *token, char *line) {
00342     netsnmp_data_list_saveinfo *info;
00343     char *dataname = NULL;
00344     size_t dataname_len;
00345     void *data = NULL;
00346 
00347     /* find the stashed information about what we're parsing */
00348     info = (netsnmp_data_list_saveinfo *) netsnmp_get_list_data(saveHead, token);
00349     if (!info) {
00350         snmp_log(LOG_WARNING, "netsnmp_read_data_callback called without previously registered subparser");
00351         return;
00352     }
00353 
00354     /* read in the token */
00355     line =
00356         read_config_read_data(ASN_OCTET_STR, line,
00357                               &dataname, &dataname_len);
00358 
00359     if (!line || !dataname)
00360         return;
00361 
00362     /* call the sub-parser to read the rest */
00363     data = (info->data_list_read_ptr)(line, strlen(line));
00364 
00365     if (!data) {
00366         free(dataname);
00367         return;
00368     }
00369 
00370     /* add to the datalist */
00371     netsnmp_add_list_data(info->datalist,
00372                           netsnmp_create_data_list(dataname, data,
00373                                                    info->data_list_free_ptr));
00374 
00375     return;
00376 }