data_list.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:12k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * netsnmp_data_list.c
  3.  *
  4.  * $Id: data_list.c,v 5.7 2004/06/28 12:20:23 rstory Exp $
  5.  */
  6. #include <net-snmp/net-snmp-config.h>
  7. #include <net-snmp/net-snmp-includes.h>
  8. #if HAVE_DMALLOC_H
  9. #include <dmalloc.h>
  10. #endif
  11. /*
  12.  * prototypes
  13.  */
  14. NETSNMP_INLINE void
  15. netsnmp_data_list_add_node(netsnmp_data_list **head, netsnmp_data_list *node);
  16. /** @defgroup data_list generic linked-list data handling with a string as a key.
  17.  * @ingroup library
  18.  * @{
  19. */
  20. /** frees the data and a name at a given data_list node.
  21.  * Note that this doesn't free the node itself.
  22.  * @param node the node for which the data should be freed
  23.  */
  24. NETSNMP_INLINE void
  25. netsnmp_free_list_data(netsnmp_data_list *node)
  26. {
  27.     Netsnmp_Free_List_Data *beer;
  28.     if (!node)
  29.         return;
  30.     beer = node->free_func;
  31.     if (beer)
  32.         (beer) (node->data);
  33.     SNMP_FREE(node->name);
  34. }
  35. /** frees all data and nodes in a list.
  36.  * @param head the top node of the list to be freed.
  37.  */
  38. NETSNMP_INLINE void
  39. netsnmp_free_all_list_data(netsnmp_data_list *head)
  40. {
  41.     netsnmp_data_list *tmpptr;
  42.     for (; head;) {
  43.         netsnmp_free_list_data(head);
  44.         tmpptr = head;
  45.         head = head->next;
  46.         SNMP_FREE(tmpptr);
  47.     }
  48. }
  49. /** adds creates a data_list node given a name, data and a free function ptr.
  50.  * @param name the name of the node to cache the data.
  51.  * @param data the data to be stored under that name
  52.  * @param beer A function that can free the data pointer (in the future)
  53.  * @return a newly created data_list node which can be given to the netsnmp_add_list_data function.
  54.  */
  55. NETSNMP_INLINE netsnmp_data_list *
  56. netsnmp_create_data_list(const char *name, void *data,
  57.                          Netsnmp_Free_List_Data * beer)
  58. {
  59.     netsnmp_data_list *node = SNMP_MALLOC_TYPEDEF(netsnmp_data_list);
  60.     if (!node)
  61.         return NULL;
  62.     node->name = strdup(name);
  63.     node->data = data;
  64.     node->free_func = beer;
  65.     return node;
  66. }
  67. /** adds data to a datalist
  68.  * @note netsnmp_data_list_add_node is preferred
  69.  * @param head a pointer to the head node of a data_list
  70.  * @param node a node to stash in the data_list
  71.  */
  72. /**  */
  73. NETSNMP_INLINE void
  74. netsnmp_add_list_data(netsnmp_data_list **head, netsnmp_data_list *node)
  75. {
  76.     netsnmp_data_list_add_node(head, node);
  77. }
  78. /** adds data to a datalist
  79.  * @param head a pointer to the head node of a data_list
  80.  * @param node a node to stash in the data_list
  81.  */
  82. NETSNMP_INLINE void
  83. netsnmp_data_list_add_node(netsnmp_data_list **head, netsnmp_data_list *node)
  84. {
  85.     netsnmp_data_list *ptr;
  86.     netsnmp_assert(NULL != head);
  87.     netsnmp_assert(NULL != node);
  88.     netsnmp_assert(NULL != node->name);
  89.     if (!*head) {
  90.         *head = node;
  91.         return;
  92.     }
  93.     DEBUGMSGTL(("data_list","adding key '%s'n", node->name));
  94.     if (0 == strcmp(node->name, (*head)->name)) {
  95.         netsnmp_assert("list key" == "is unique"); /* always fail */
  96.         snmp_log(LOG_WARNING,
  97.                  "WARNING: adding duplicate key '%s' to data listn",
  98.                  node->name);
  99.     }
  100.     for (ptr = *head; ptr->next != NULL; ptr = ptr->next) {
  101.         netsnmp_assert(NULL != ptr->name);
  102.         if (0 == strcmp(node->name, ptr->name)) {
  103.             netsnmp_assert("list key" == "is unique"); /* always fail */
  104.             snmp_log(LOG_WARNING,
  105.                      "WARNING: adding duplicate key '%s' to data listn",
  106.                      node->name);
  107.         }
  108.     }
  109.     netsnmp_assert(NULL != ptr);
  110.     if (ptr)                    /* should always be true */
  111.         ptr->next = node;
  112. }
  113. /** adds data to a datalist
  114.  * @param head a pointer to the head node of a data_list
  115.  * @param name the name of the node to cache the data.
  116.  * @param data the data to be stored under that name
  117.  * @param beer A function that can free the data pointer (in the future)
  118.  * @return a newly created data_list node which was inserted in the list
  119.  */
  120. NETSNMP_INLINE netsnmp_data_list *
  121. netsnmp_data_list_add_data(netsnmp_data_list **head, const char *name,
  122.                            void *data, Netsnmp_Free_List_Data * beer)
  123. {
  124.     netsnmp_data_list *node = netsnmp_create_data_list(name, data, beer);
  125.     if(NULL == node) {
  126.         snmp_log(LOG_ERR,"could not allocate memory for node.");
  127.         return NULL;
  128.     }
  129.     
  130.     netsnmp_add_list_data(head, node);
  131.     return node;
  132. }
  133. /** returns a data_list node's data for a given name within a data_list
  134.  * @param head the head node of a data_list
  135.  * @param name the name to find
  136.  * @return a pointer to the data cached at that node
  137.  */
  138. NETSNMP_INLINE void    *
  139. netsnmp_get_list_data(netsnmp_data_list *head, const char *name)
  140. {
  141.     for (; head; head = head->next)
  142.         if (head->name && strcmp(head->name, name) == 0)
  143.             break;
  144.     if (head)
  145.         return head->data;
  146.     return NULL;
  147. }
  148. /** returns a data_list node for a given name within a data_list
  149.  * @param head the head node of a data_list
  150.  * @param name the name to find
  151.  * @return a pointer to the data_list node
  152.  */
  153. NETSNMP_INLINE netsnmp_data_list    *
  154. netsnmp_get_list_node(netsnmp_data_list *head, const char *name)
  155. {
  156.     for (; head; head = head->next)
  157.         if (head->name && strcmp(head->name, name) == 0)
  158.             break;
  159.     if (head)
  160.         return head;
  161.     return NULL;
  162. }
  163. /** Removes a named node from a data_list (and frees it)
  164.  * @param realhead a pointer to the head node of a data_list
  165.  * @param name the name to find and remove
  166.  * @return 0 on successful find-and-delete, 1 otherwise.
  167.  */
  168. int
  169. netsnmp_remove_list_node(netsnmp_data_list **realhead, const char *name)
  170. {
  171.     netsnmp_data_list *head, *prev;
  172.     for (head = *realhead, prev = NULL; head;
  173.          prev = head, head = head->next) {
  174.         if (head->name && strcmp(head->name, name) == 0) {
  175.             if (prev)
  176.                 prev->next = head->next;
  177.             else
  178.                 *realhead = head->next;
  179.             netsnmp_free_list_data(head);
  180.             free(head);
  181.             return 0;
  182.         }
  183.     }
  184.     return 1;
  185. }
  186. /** used to store registered save/parse handlers (specifically, parsing info) */
  187. static netsnmp_data_list *saveHead;
  188. /** registers to store a data_list set of data at persistant storage time
  189.  *
  190.  * @param datalist the data to be saved
  191.  * @param type the name of the application to save the data as.  If left NULL the default application name that was registered during the init_snmp call will be used (recommended).
  192.  * @param token the unique token identifier string to use as the first word in the persistent file line.
  193.  * @param data_list_save_ptr a function pointer which will be called to save the rest of the data to a buffer.
  194.  * @param data_list_read_ptr a function pointer which can read the remainder of a saved line and return the application specific void * pointer.
  195.  * @param data_list_free_ptr a function pointer which will be passed to the data node for freeing it in the future when/if the list/node is cleaned up or destroyed.
  196.  */
  197. void
  198. netsnmp_register_save_list(netsnmp_data_list **datalist,
  199.                            const char *type, const char *token,
  200.                            Netsnmp_Save_List_Data *data_list_save_ptr,
  201.                            Netsnmp_Read_List_Data *data_list_read_ptr,
  202.                            Netsnmp_Free_List_Data *data_list_free_ptr) {
  203.     netsnmp_data_list_saveinfo *info =
  204.         SNMP_MALLOC_TYPEDEF(netsnmp_data_list_saveinfo);
  205.     if (!info) {
  206.         snmp_log(LOG_ERR, "couldn't malloc a netsnmp_data_list_saveinfo typedef");
  207.         return;
  208.     }
  209.     info->datalist = datalist;
  210.     info->token = token;
  211.     info->type = type;
  212.     if (!info->type) {
  213.         info->type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
  214.                                            NETSNMP_DS_LIB_APPTYPE);
  215.     }
  216.     /* function which will save the data */
  217.     info->data_list_save_ptr = data_list_save_ptr;
  218.     if (data_list_save_ptr)
  219.         snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
  220.                                netsnmp_save_all_data_callback, info);
  221.     /* function which will read the data back in */
  222.     info->data_list_read_ptr = data_list_read_ptr;
  223.     if (data_list_read_ptr) {
  224.         /** @todo netsnmp_register_save_list should handle the same token name being saved from different types? */
  225.         netsnmp_add_list_data(&saveHead,
  226.                               netsnmp_create_data_list(token, info, NULL));
  227.         register_config_handler(type, token, netsnmp_read_data_callback,
  228.                                 NULL /* XXX */, NULL);
  229.     }
  230.     info->data_list_free_ptr = data_list_free_ptr;
  231. }
  232. /** intended to be registerd as a callback operation.
  233.  * It should be registered using:
  234.  *
  235.  * snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, netsnmp_save_all_data_callback, INFO_POINTER);
  236.  *
  237.  * where INFO_POINTER is a pointer to a netsnmp_data_list_saveinfo object containing apporpriate registration information
  238.  */
  239. int
  240. netsnmp_save_all_data_callback(int major, int minor,
  241.                                void *serverarg, void *clientarg) {
  242.     netsnmp_data_list_saveinfo *info = clientarg;
  243.     if (!clientarg) {
  244.         snmp_log(LOG_WARNING, "netsnmp_save_all_data_callback called with no passed data");
  245.         return SNMP_ERR_NOERROR;
  246.     }
  247.     netsnmp_save_all_data(*(info->datalist), info->type, info->token,
  248.                           info->data_list_save_ptr);
  249.     return SNMP_ERR_NOERROR;
  250. }    
  251. /** intended to be called as a callback during persistent save operations.
  252.  * See the netsnmp_save_all_data_callback for where this is typically used. */
  253. int
  254. netsnmp_save_all_data(netsnmp_data_list *head,
  255.                       const char *type, const char *token,
  256.                       Netsnmp_Save_List_Data * data_list_save_ptr)
  257. {
  258.     char buf[SNMP_MAXBUF], *cp;
  259.     for (; head; head = head->next) {
  260.         if (head->name) {
  261.             /* save begining of line */
  262.             snprintf(buf, sizeof(buf), "%s ", token);
  263.             cp = buf + strlen(buf);
  264.             cp = read_config_save_octet_string(cp, (u_char*)head->name,
  265.                                                strlen(head->name));
  266.             *cp++ = ' ';
  267.             /* call registered function to save the rest */
  268.             if (!(data_list_save_ptr)(cp,
  269.                                       sizeof(buf) - strlen(buf),
  270.                                       head->data)) {
  271.                 read_config_store(type, buf);
  272.             }
  273.         }
  274.     }
  275.     return SNMP_ERR_NOERROR;
  276. }
  277. /** @todo make netsnmp_read_data_callback deal with a free routine */
  278. /** intended to be registerd as a .conf parser
  279.  * It should be registered using:
  280.  *
  281.  * register_app_config_handler("token", netsnmp_read_data_callback, XXX)
  282.  *
  283.  * where INFO_POINTER is a pointer to a netsnmp_data_list_saveinfo object containing apporpriate registration information
  284.  */
  285. void
  286. netsnmp_read_data_callback(const char *token, char *line) {
  287.     netsnmp_data_list_saveinfo *info;
  288.     char *dataname = NULL;
  289.     size_t dataname_len;
  290.     void *data = NULL;
  291.     /* find the stashed information about what we're parsing */
  292.     info = netsnmp_get_list_data(saveHead, token);
  293.     if (!info) {
  294.         snmp_log(LOG_WARNING, "netsnmp_read_data_callback called without previously registered subparser");
  295.         return;
  296.     }
  297.     /* read in the token */
  298.     line =
  299.         read_config_read_data(ASN_OCTET_STR, line,
  300.                               &dataname, &dataname_len);
  301.     if (!line || !dataname)
  302.         return;
  303.     /* call the sub-parser to read the rest */
  304.     data = (info->data_list_read_ptr)(line, strlen(line));
  305.     if (!data) {
  306.         free(dataname);
  307.         return;
  308.     }
  309.     /* add to the datalist */
  310.     netsnmp_add_list_data(info->datalist,
  311.                           netsnmp_create_data_list(dataname, data,
  312.                                                    info->data_list_free_ptr));
  313.     return;
  314. }