network test
[oweals/gnunet.git] / src / sysmon / gnunet-daemon-sysmon.c
index cfd075debe658a9b8e5911b7f911c6c0c05c1d2c..387c4bd2e5202296d4e1eee9758014a056cc990a 100644 (file)
 #include "gnunet_util_lib.h"
 #include "gnunet_statistics_service.h"
 
+enum operation
+{
+  o_internal,
+  o_command
+};
+
+
 enum type
 {
   t_static,
@@ -39,21 +46,75 @@ enum value
   v_string
 };
 
+/**
+ * A system property to monitor
+ */
 struct SysmonProperty
 {
+  /**
+   * Next element in in the DLL
+   */
   struct SysmonProperty *next;
-  struct SysmonProperty *prev;
-
- char * desc;
- int type;
- int value_type;
- struct GNUNET_TIME_Relative interval;
 
- uint64_t num_val;
- char * str_val;
+  /**
+   * Previous element in in the DLL
+   */
+  struct SysmonProperty *prev;
 
- GNUNET_SCHEDULER_TaskIdentifier task_id;
- GNUNET_SCHEDULER_Task task;
+  /**
+   * Description used for statistics valuesd
+   */
+  char * desc;
+
+  /**
+   * Type
+   */
+  int type;
+
+  /**
+   * Value type
+   */
+  int value_type;
+
+  /**
+   * Execution interval
+   */
+  struct GNUNET_TIME_Relative interval;
+
+  /**
+   * Command
+   */
+  char * cmd;
+
+  /**
+   * Command arguments
+   */
+  char * cmd_args;
+
+  /**
+   * Command execution handle
+   */
+  void * cmd_exec_handle;
+
+  /**
+   * Numerical value
+   */
+  uint64_t num_val;
+
+  /**
+   * String value
+   */
+  char * str_val;
+
+  /**
+   * Task id
+   */
+  GNUNET_SCHEDULER_TaskIdentifier task_id;
+
+  /**
+   * Task handle
+   */
+  GNUNET_SCHEDULER_Task task;
 
 };
 
@@ -76,7 +137,6 @@ struct GNUNET_STATISTICS_Handle *stats;
 /**
  * Shutdown task
  */
-
 GNUNET_SCHEDULER_TaskIdentifier end_task;
 
 struct SysmonProperty *sp_head;
@@ -101,6 +161,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   next = sp_head;
   while (NULL != (sp = next))
   {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping `%s' \n", sp->desc);
       GNUNET_CONTAINER_DLL_remove (sp_head, sp_tail, sp);
       next = sp->next;
       if (GNUNET_SCHEDULER_NO_TASK != sp->task_id)
@@ -108,7 +169,9 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
         GNUNET_SCHEDULER_cancel (sp->task_id);
         sp->task_id = GNUNET_SCHEDULER_NO_TASK;
       }
-      GNUNET_free_non_null (sp->desc);
+      GNUNET_free_non_null (sp->cmd);
+      GNUNET_free_non_null (sp->cmd_args);
+      GNUNET_free (sp->desc);
       GNUNET_free (sp);
   }
 
@@ -149,6 +212,68 @@ put_property (struct SysmonProperty *sp)
   return GNUNET_OK;
 }
 
+static void
+update_uptime (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct SysmonProperty *sp = cls;
+  sp->num_val ++;
+  put_property (sp);
+}
+
+static void
+exec_cmd_proc (void *cls, const char *line)
+{
+  struct SysmonProperty *sp = cls;
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
+  if (NULL == line)
+  {
+      GNUNET_OS_command_stop (sp->cmd_exec_handle);
+      sp->cmd_exec_handle = NULL;
+      return;
+  }
+
+  switch (sp->value_type) {
+    case v_numeric:
+      if (1 != sscanf (line, "%lu", &sp->num_val))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Command output was not a numerical value: `%s'\n", line);
+        return;
+      }
+      break;
+    case v_string:
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "NOT IMPLEMENTED\n");
+      break;
+    default:
+      break;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
+  put_property (sp);
+
+
+}
+
+static void
+exec_cmd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct SysmonProperty *sp = cls;
+  GNUNET_assert (NULL != sp->cmd);
+
+  if (NULL != sp->cmd_exec_handle)
+  {
+    GNUNET_OS_command_stop (sp->cmd_exec_handle);
+    sp->cmd_exec_handle = NULL;
+    GNUNET_break (0);
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property `%s': command `%s' `%s'\n", sp->desc, sp->cmd, sp->cmd_args);
+  if (NULL == (sp->cmd_exec_handle = GNUNET_OS_command_run (&exec_cmd_proc, sp,
+      GNUNET_TIME_UNIT_SECONDS,
+      sp->cmd, sp->cmd,
+      sp->cmd_args,
+      NULL)))
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property `%s': command `%s' failed\n", sp->desc, sp->cmd);
+}
+
 static void
 load_property (void *cls,
                const char *section)
@@ -162,25 +287,54 @@ load_property (void *cls,
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading section `%s'\n", section);
 
-  if (GNUNET_NO == GNUNET_CONFIGURATION_have_value(properties, section, "TYPE"))
+  if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section, "TYPE"))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
         "TYPE", section);
     return;
   }
-  if (GNUNET_NO == GNUNET_CONFIGURATION_have_value(properties, section,"VALUE"))
+  if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"VALUE"))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
         "VALUE", section);
     return;
   }
+  if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"DESCRIPTION"))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
+        "DESCRIPTION", section);
+    return;
+  }
+  if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"CMD"))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
+        "CMD", section);
+    return;
+  }
   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
 
   /* description */
-  GNUNET_CONFIGURATION_get_value_string(properties, section, "DESCRIPTION", &sp->desc);
+  GNUNET_CONFIGURATION_get_value_string (properties, section, "DESCRIPTION", &sp->desc);
+
+  /* cmd */
+  GNUNET_CONFIGURATION_get_value_string (properties, section, "CMD", &tmp);
+  char *args = "";
+  if (NULL != strchr (tmp, ' '))
+  {
+      args = strchr (tmp, ' ');
+      if (strlen (args) > 1)
+      {
+          args[0] = '\0';
+          args++;
+      }
+  }
+  sp->cmd = GNUNET_strdup (tmp);
+  sp->cmd_args = GNUNET_strdup (args);
+  GNUNET_free (tmp);
+  sp->task = &exec_cmd;
 
   /* type */
-  GNUNET_CONFIGURATION_get_value_string(properties, section, "TYPE", &tmp);
+  GNUNET_CONFIGURATION_get_value_string (properties, section, "TYPE", &tmp);
   to_lower_str (tmp);
   if (0 == strcasecmp(tmp, "static"))
     sp->type = t_static;
@@ -197,7 +351,7 @@ load_property (void *cls,
   GNUNET_free (tmp);
 
   /* value */
-  GNUNET_CONFIGURATION_get_value_string(properties, section, "VALUE", &tmp);
+  GNUNET_CONFIGURATION_get_value_string (properties, section, "VALUE", &tmp);
   to_lower_str (tmp);
   if (0 == strcasecmp(tmp, "numeric"))
     sp->value_type = v_numeric;
@@ -214,25 +368,28 @@ load_property (void *cls,
   GNUNET_free (tmp);
 
   /* interval */
+  if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"INTERVAL"))
+    sp->interval = GNUNET_TIME_UNIT_MINUTES;
+  else
+  {
+    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (properties, section, "INTERVAL", &sp->interval))
+    {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+            _("Could not parse execution interval for `%s', set to default 60 sec.\n"), section);
+        sp->interval = GNUNET_TIME_UNIT_MINUTES;
+    }
+  }
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded property `%s': type %u, value %u,\n",
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded property `%s': %s, %s, interval %llu\n",
       (NULL != sp->desc) ? sp->desc: "<undefined>",
-      sp->type, sp->value_type);
+      (t_continous == sp->type) ? "continious" : "static",
+      (v_numeric == sp->value_type) ? "numeric" : "string",
+      sp->interval.rel_value);
 
   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
 
 }
 
-static void
-update_uptime (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct SysmonProperty *sp = cls;
-  sp->task_id = GNUNET_SCHEDULER_NO_TASK;
-  sp->num_val ++;
-  put_property (sp);
-  sp->task_id = GNUNET_SCHEDULER_add_delayed (sp->interval, sp->task, sp);
-}
-
 static int
 load_default_properties (void)
 {
@@ -242,7 +399,7 @@ load_default_properties (void)
 
   /* GNUnet vcs revision */
   unsigned int revision;
-
+return GNUNET_OK;
   /* version */
 #ifdef VERSION
   if (3 != sscanf (VERSION, "%u.%u.%u", &ver[0], &ver[1], &ver[2]))
@@ -311,6 +468,18 @@ load_default_properties (void)
   return GNUNET_OK;
 }
 
+
+static void
+run_property (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct SysmonProperty *sp = cls;
+  sp->task_id = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running continous property `%s' \n", sp->desc);
+  sp->task (cls, tc);
+  sp->task_id = GNUNET_SCHEDULER_add_delayed (sp->interval, &run_property, sp);
+}
+
+
 static int
 run_properties (void)
 {
@@ -327,11 +496,10 @@ run_properties (void)
       {
           if (NULL == sp->task)
           {
-            continue;
             GNUNET_break (0);
+            continue;
           }
-          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running continous property `%s' \n", sp->desc);
-          sp->task_id = GNUNET_SCHEDULER_add_now (&update_uptime, sp);
+          sp->task_id = GNUNET_SCHEDULER_add_now (&run_property, sp);
       }
   }
   return GNUNET_OK;