Hostinfo day 5: Implement first round of static host commands.
[virt-hostinfo.git] / hostinfod / configuration.c
index 90200f8..86a43dc 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <fnmatch.h>
 
 #include <apr_general.h>
 #include <apr_strings.h>
 #include "hostinfod.h"
 
 typedef int (*process_line_fn) (const char *path, int lineno,
-                               const char *key, const char *value);
+                               const char *key, const char *value,
+                               void *data);
 typedef int (*process_section_fn) (const char *path, int lineno,
-                                  const char *section);
+                                  const char *section,
+                                  void *data);
 static void process_conf_file (const char *path, int exit_if_not_exist,
                               process_line_fn process_line,
-                              process_section_fn process_section);
+                              process_section_fn process_section,
+                              void *data);
 static int get_bool (const char *str);
 
 /* Read the main configuration file. */
-static int main_process_line (const char *path, int lineno, const char *key, const char *value);
+static int main_process_line (const char *path, int lineno, const char *key, const char *value, void *data);
 
 void
 read_main_conf_file (void)
 {
-  process_conf_file (conf_file, 0, main_process_line, NULL);
+  process_conf_file (conf_file, 0, main_process_line, NULL, NULL);
 }
 
 static int
 main_process_line (const char *path, int lineno,
-                  const char *key, const char *value)
+                  const char *key, const char *value,
+                  void *data)
 {
   int bool;
 
@@ -66,6 +71,13 @@ main_process_line (const char *path, int lineno,
       return -1;
     }
     socket_dir = apr_pstrdup (pool, value);
+  } else if (strcasecmp (key, "libvirt") == 0) {
+    if (!value) {
+      error ("%s:%d: directive is empty: %s", path, lineno, key);
+      return -1;
+    }
+    if (!libvirt_uri_set_on_cmdline)
+      libvirt_uri = apr_pstrdup (pool, value);
   } else if (strcasecmp (key, "verbose") == 0) {
     bool = get_bool (value);
     if (bool == -1) {
@@ -90,11 +102,102 @@ main_process_line (const char *path, int lineno,
   return 0;
 }
 
+/* Check that 'cmd' is enabled for the named guest, and that
+ * it is not being called too frequently.
+ *
+ * XXX Rereading the configuration file each time is possibly
+ * inefficient.
+ *
+ * Returns 0 = proceed, -1 = fail.
+ */
+static int guests_process_line (const char *path, int lineno,
+                               const char *key, const char *value,
+                               void *data);
+static int guests_process_section (const char *path, int lineno,
+                                  const char *section,
+                                  void *data);
+
+struct guests_data {
+  const char *name;            /* guest "driver-name" */
+  const char *cmd;             /* command being tested */
+  int in_section;              /* currently processing the right section? */
+  double interval;             /* interval for this guest (0 = any) */
+  int enabled;                 /* is command enabled? */
+};
+
+void
+check_guests_file (struct guest_description *hval, const char *cmd,
+                  double *interval, int *enabled)
+{
+  struct guests_data *data = apr_palloc (hval->rpool, sizeof *data);
+
+  data->name = hval->name;
+  data->cmd = cmd;
+  data->in_section = 0;
+  data->interval = 60.;                /* default */
+  data->enabled = 0;           /* default */
+
+  process_conf_file (guests_file, 1,
+                    guests_process_line, guests_process_section, data);
+
+  *interval = data->interval;
+  *enabled = data->enabled;
+}
+
+static int
+guests_process_line (const char *path, int lineno,
+                    const char *key, const char *value,
+                    void *datav)
+{
+  struct guests_data *data = datav;
+  int bool;
+
+  if (!data->in_section)
+    return 0;
+
+  if (strcasecmp (key, "interval") == 0) {
+    if (strcasecmp (value, "any") == 0)
+      data->interval = 0;
+    else {
+      if (sscanf (value, "%lg", &data->interval) != 1) {
+       error ("%s:%d: %s: not a valid decimal number", path, lineno, key);
+       return -1;
+      }
+    }
+  } else if (strcasecmp (key, data->cmd) == 0) {
+    bool = get_bool (value);
+    if (bool == -1) {
+      error ("%s:%d: %s: not a valid boolean - use 1 or 0", path, lineno, key);
+      return -1;
+    }
+    data->enabled = bool;
+  }
+
+  return 0;
+}
+
+static int
+guests_process_section (const char *path, int lineno,
+                       const char *section,
+                       void *datav)
+{
+  struct guests_data *data = datav;
+  int flags = 0;
+
+#ifdef FNM_CASEFOLD
+  flags |= FNM_CASEFOLD;
+#endif
+
+  data->in_section = fnmatch (section, data->name, flags) == 0;
+  return 0;
+}
+
 /* Configuration file parser. */
 static void
 process_conf_file (const char *path, int exit_if_not_exist,
                   process_line_fn process_line,
-                  process_section_fn process_section)
+                  process_section_fn process_section,
+                  void *data)
 {
   static const char *whitespace = " \t\n\v";
   FILE *fp;
@@ -142,15 +245,15 @@ process_conf_file (const char *path, int exit_if_not_exist,
        exit (1);
       }
 
-      debug ("configuration file: section [%s]", line);
+      debug ("configuration file: section [%s]", &line[1]);
 
       if (!process_section) {
        error ("%s:%d: unexpected section header ([%s]) in file",
-              path, lineno, line);
+              path, lineno, &line[1]);
        exit (1);
       }
 
-      if (process_section (path, lineno, line) == -1)
+      if (process_section (path, lineno, &line[1], data) == -1)
        exit (1);
     }
     else {                     /* Key value */
@@ -159,14 +262,14 @@ process_conf_file (const char *path, int exit_if_not_exist,
       key = line;
       value = key_len < real_len ? &line[key_len+1] : NULL;
       if (value) {
-       value += strspn (line, whitespace);
+       value += strspn (value, whitespace);
        if (value[0] == '\0')
          value = NULL;
       }
 
       debug ("configuration file: key '%s', value '%s'", key, value);
 
-      if (process_line && process_line (path, lineno, key, value) == -1)
+      if (process_line && process_line (path, lineno, key, value, data) == -1)
        exit (1);
     }
   }