Merge branch 'collectd-5.8'
[collectd.git] / src / snmp_agent.c
index 0908b4e..48d9f86 100644 (file)
@@ -71,7 +71,7 @@ struct data_definition_s {
   char *type;
   char *type_instance;
   const table_definition_t *table;
-  _Bool is_instance;
+  bool is_instance;
   oid_t *oids;
   size_t oids_len;
   double scale;
@@ -90,7 +90,7 @@ struct snmp_agent_ctx_s {
 };
 typedef struct snmp_agent_ctx_s snmp_agent_ctx_t;
 
-static snmp_agent_ctx_t *g_agent = NULL;
+static snmp_agent_ctx_t *g_agent;
 
 #define CHECK_DD_TYPE(_dd, _p, _pi, _t, _ti)                                   \
   (_dd->plugin ? !strcmp(_dd->plugin, _p) : 0) &&                              \
@@ -98,6 +98,7 @@ static snmp_agent_ctx_t *g_agent = NULL;
       (_dd->type ? !strcmp(_dd->type, _t) : 0) &&                              \
       (_dd->type_instance ? !strcmp(_dd->type_instance, _ti) : 1)
 
+static int snmp_agent_shutdown(void);
 static void *snmp_agent_thread_run(void *arg);
 static int snmp_agent_register_oid(oid_t *oid, Netsnmp_Node_Handler *handler);
 static int snmp_agent_set_vardata(void *dst_buf, size_t *dst_buf_len,
@@ -123,7 +124,7 @@ static int snmp_agent_oid_to_string(char *buf, size_t buf_size,
   char *oid_str_ptr[MAX_OID_LEN];
 
   for (size_t i = 0; i < o->oid_len; i++) {
-    ssnprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]);
+    snprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]);
     oid_str_ptr[i] = oid_str[i];
   }
 
@@ -165,7 +166,7 @@ static void snmp_agent_dump_data(void) {
         DEBUG(PLUGIN_NAME ":     TypeInstance: %s", dd->type_instance);
       for (size_t i = 0; i < dd->oids_len; i++) {
         snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &dd->oids[i]);
-        DEBUG(PLUGIN_NAME ":     OID[%zu]: %s", i, oid_str);
+        DEBUG(PLUGIN_NAME ":     OID[%" PRIsz "]: %s", i, oid_str);
       }
       DEBUG(PLUGIN_NAME ":   Scale: %g", dd->scale);
       DEBUG(PLUGIN_NAME ":   Shift: %g", dd->shift);
@@ -189,7 +190,7 @@ static void snmp_agent_dump_data(void) {
       DEBUG(PLUGIN_NAME ":   TypeInstance: %s", dd->type_instance);
     for (size_t i = 0; i < dd->oids_len; i++) {
       snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &dd->oids[i]);
-      DEBUG(PLUGIN_NAME ":   OID[%zu]: %s", i, oid_str);
+      DEBUG(PLUGIN_NAME ":   OID[%" PRIsz "]: %s", i, oid_str);
     }
     DEBUG(PLUGIN_NAME ":   Scale: %g", dd->scale);
     DEBUG(PLUGIN_NAME ":   Shift: %g", dd->shift);
@@ -282,7 +283,8 @@ static int snmp_agent_validate_data(void) {
   return 0;
 }
 
-static void snmp_agent_generate_oid2string(oid_t *oid, size_t offset, char *key) {
+static void snmp_agent_generate_oid2string(oid_t *oid, size_t offset,
+                                           char *key) {
   int key_len = oid->oid[offset];
   int i;
 
@@ -368,9 +370,9 @@ static int snmp_agent_table_row_remove(table_definition_t *td,
       .severity = NOTIF_WARNING, .time = cdtime(), .plugin = PLUGIN_NAME};
   sstrncpy(n.host, hostname_g, sizeof(n.host));
   sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance));
-  ssnprintf(n.message, sizeof(n.message),
-            "Removed data row from table %s instance %s index %d", td->name,
-            ins, (index != NULL) ? *index : -1);
+  snprintf(n.message, sizeof(n.message),
+           "Removed data row from table %s instance %s index %d", td->name, ins,
+           (index != NULL) ? *index : -1);
   plugin_dispatch_notification(&n);
 
   if (td->index_oid.oid_len) {
@@ -420,28 +422,6 @@ static void snmp_agent_free_data(data_definition_t **dd) {
     for (size_t i = 0; i < (*dd)->oids_len; i++)
       unregister_mib((*dd)->oids[i].oid, (*dd)->oids[i].oid_len);
   }
-  if (!(*dd)->table->index_oid.oid_len) {
-    char *instance;
-
-    c_avl_iterator_t *iter = c_avl_get_iterator((*dd)->table->instance_index);
-    while (c_avl_iterator_next(iter, (void *)&instance, (void *)&instance) ==
-           0) {
-      for (size_t i = 0; i < (*dd)->oids_len; i++)
-        snmp_agent_unregister_oid_string(&(*dd)->oids[i], instance);
-    }
-    c_avl_iterator_destroy(iter);
-  } else {
-    /* unregister all table OIDs */
-    int *index;
-    char *value;
-
-    c_avl_iterator_t *iter = c_avl_get_iterator((*dd)->table->index_instance);
-    while (c_avl_iterator_next(iter, (void *)&index, (void *)&value) == 0) {
-      for (size_t i = 0; i < (*dd)->oids_len; i++)
-        snmp_agent_unregister_oid_index(&(*dd)->oids[i], *index);
-    }
-    c_avl_iterator_destroy(iter);
-  }
 
   sfree((*dd)->name);
   sfree((*dd)->plugin);
@@ -455,6 +435,43 @@ static void snmp_agent_free_data(data_definition_t **dd) {
   return;
 }
 
+static void snmp_agent_free_table_columns(table_definition_t *td) {
+  if (td->columns == NULL)
+    return;
+
+  for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) {
+    data_definition_t *dd = de->value;
+
+    if (td->index_oid.oid_len) {
+      int *index;
+      char *instance;
+
+      c_avl_iterator_t *iter = c_avl_get_iterator(td->index_instance);
+      while (c_avl_iterator_next(iter, (void *)&index, (void *)&instance) ==
+             0) {
+        for (size_t i = 0; i < dd->oids_len; i++)
+          snmp_agent_unregister_oid_index(&dd->oids[i], *index);
+      }
+      c_avl_iterator_destroy(iter);
+    } else {
+      char *instance;
+
+      c_avl_iterator_t *iter = c_avl_get_iterator(dd->table->instance_index);
+      while (c_avl_iterator_next(iter, (void *)&instance, (void *)&instance) ==
+             0) {
+        for (size_t i = 0; i < dd->oids_len; i++)
+          snmp_agent_unregister_oid_string(&dd->oids[i], instance);
+      }
+      c_avl_iterator_destroy(iter);
+    }
+
+    snmp_agent_free_data(&dd);
+  }
+
+  llist_destroy(td->columns);
+  td->columns = NULL;
+} /* void snmp_agent_free_table_columns */
+
 static void snmp_agent_free_table(table_definition_t **td) {
 
   if (td == NULL || *td == NULL)
@@ -463,23 +480,20 @@ static void snmp_agent_free_table(table_definition_t **td) {
   if ((*td)->size_oid.oid_len)
     unregister_mib((*td)->size_oid.oid, (*td)->size_oid.oid_len);
 
+  /* Unregister Index OIDs */
   if ((*td)->index_oid.oid_len) {
     int *index;
-    char *value;
+    char *instance;
 
     c_avl_iterator_t *iter = c_avl_get_iterator((*td)->index_instance);
-    while (c_avl_iterator_next(iter, (void *)&index, (void *)&value) == 0)
+    while (c_avl_iterator_next(iter, (void *)&index, (void *)&instance) == 0)
       snmp_agent_unregister_oid_index(&(*td)->index_oid, *index);
 
     c_avl_iterator_destroy(iter);
   }
 
-  for (llentry_t *de = llist_head((*td)->columns); de != NULL; de = de->next) {
-    data_definition_t *dd = de->value;
-    snmp_agent_free_data(&dd);
-  }
-
-  llist_destroy((*td)->columns);
+  /* Unregister all table columns and their registered OIDs */
+  snmp_agent_free_table_columns(*td);
 
   void *key = NULL;
   void *value = NULL;
@@ -616,9 +630,9 @@ snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler,
 
         if (dd->is_instance) {
           requests->requestvb->type = ASN_OCTET_STR;
-          snmp_set_var_typed_value(requests->requestvb,
-                                   requests->requestvb->type, (const u_char *)instance,
-                                   strlen((instance)));
+          snmp_set_var_typed_value(
+              requests->requestvb, requests->requestvb->type,
+              (const u_char *)instance, strlen((instance)));
 
           pthread_mutex_unlock(&g_agent->lock);
 
@@ -1103,12 +1117,6 @@ static int snmp_agent_config_table(oconfig_item_t *ci) {
     }
   }
 
-  llentry_t *entry = llentry_create(td->name, td);
-  if (entry == NULL) {
-    snmp_agent_free_table(&td);
-    return -ENOMEM;
-  }
-
   td->instance_index =
       c_avl_create((int (*)(const void *, const void *))strcmp);
   if (td->instance_index == NULL) {
@@ -1123,6 +1131,11 @@ static int snmp_agent_config_table(oconfig_item_t *ci) {
     return -ENOMEM;
   }
 
+  llentry_t *entry = llentry_create(td->name, td);
+  if (entry == NULL) {
+    snmp_agent_free_table(&td);
+    return -ENOMEM;
+  }
   llist_append(g_agent->tables, entry);
 
   return 0;
@@ -1305,9 +1318,9 @@ static int snmp_agent_update_index(table_definition_t *td,
       .severity = NOTIF_OKAY, .time = cdtime(), .plugin = PLUGIN_NAME};
   sstrncpy(n.host, hostname_g, sizeof(n.host));
   sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance));
-  ssnprintf(n.message, sizeof(n.message),
-            "Data row added to table %s instance %s index %d", td->name, ins,
-            (index != NULL) ? *index : -1);
+  snprintf(n.message, sizeof(n.message),
+           "Data row added to table %s instance %s index %d", td->name, ins,
+           (index != NULL) ? *index : -1);
   plugin_dispatch_notification(&n);
 
   return 0;
@@ -1364,12 +1377,21 @@ static int snmp_agent_preinit(void) {
   g_agent->tables = llist_create();
   g_agent->scalars = llist_create();
 
+  if (g_agent->tables == NULL || g_agent->scalars == NULL) {
+    ERROR(PLUGIN_NAME ": llist_create() failed");
+    llist_destroy(g_agent->scalars);
+    llist_destroy(g_agent->tables);
+    return -ENOMEM;
+  }
+
   int err;
   /* make us a agentx client. */
   err = netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE,
                                1);
   if (err != 0) {
     ERROR(PLUGIN_NAME ": Failed to set agent role (%d)", err);
+    llist_destroy(g_agent->scalars);
+    llist_destroy(g_agent->tables);
     return -1;
   }
 
@@ -1381,6 +1403,8 @@ static int snmp_agent_preinit(void) {
   err = init_agent(PLUGIN_NAME);
   if (err != 0) {
     ERROR(PLUGIN_NAME ": Failed to initialize the agent library (%d)", err);
+    llist_destroy(g_agent->scalars);
+    llist_destroy(g_agent->tables);
     return -1;
   }
 
@@ -1394,9 +1418,13 @@ static int snmp_agent_preinit(void) {
 static int snmp_agent_init(void) {
   int ret;
 
-  ret = snmp_agent_preinit();
-  if (ret != 0)
-    return ret;
+  if (g_agent == NULL || ((llist_head(g_agent->scalars) == NULL) &&
+                          (llist_head(g_agent->tables) == NULL))) {
+    ERROR(PLUGIN_NAME ": snmp_agent_init: plugin not configured");
+    return -EINVAL;
+  }
+
+  plugin_register_shutdown(PLUGIN_NAME, snmp_agent_shutdown);
 
   ret = snmp_agent_register_scalar_oids();
   if (ret != 0)
@@ -1406,13 +1434,6 @@ static int snmp_agent_init(void) {
   if (ret != 0)
     return ret;
 
-  /* create a second thread to listen for requests from AgentX*/
-  ret = pthread_create(&g_agent->thread, NULL, &snmp_agent_thread_run, NULL);
-  if (ret != 0) {
-    ERROR(PLUGIN_NAME ": Failed to create a separate thread, err %u", ret);
-    return ret;
-  }
-
   ret = pthread_mutex_init(&g_agent->lock, NULL);
   if (ret != 0) {
     ERROR(PLUGIN_NAME ": Failed to initialize mutex, err %u", ret);
@@ -1425,6 +1446,18 @@ static int snmp_agent_init(void) {
     return ret;
   }
 
+  /* create a second thread to listen for requests from AgentX*/
+  ret = pthread_create(&g_agent->thread, NULL, &snmp_agent_thread_run, NULL);
+  if (ret != 0) {
+    ERROR(PLUGIN_NAME ": Failed to create a separate thread, err %u", ret);
+    return ret;
+  }
+
+  if (llist_head(g_agent->tables) != NULL) {
+    plugin_register_write(PLUGIN_NAME, snmp_agent_collect, NULL);
+    plugin_register_missing(PLUGIN_NAME, snmp_agent_clear_missing, NULL);
+  }
+
   return 0;
 }
 
@@ -1570,7 +1603,4 @@ static int snmp_agent_config(oconfig_item_t *ci) {
 void module_register(void) {
   plugin_register_init(PLUGIN_NAME, snmp_agent_init);
   plugin_register_complex_config(PLUGIN_NAME, snmp_agent_config);
-  plugin_register_write(PLUGIN_NAME, snmp_agent_collect, NULL);
-  plugin_register_missing(PLUGIN_NAME, snmp_agent_clear_missing, NULL);
-  plugin_register_shutdown(PLUGIN_NAME, snmp_agent_shutdown);
 }