]> source.dussan.org Git - rspamd.git/commitdiff
* Add dumper to XML file (not all sections yet)
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Thu, 1 Apr 2010 15:45:35 +0000 (19:45 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Thu, 1 Apr 2010 15:45:35 +0000 (19:45 +0400)
* Add checksum to config files
* Some config parsing reorganizations:
  - post_load_config should be called after xml initialization
  - xml state machine is corrected to read main section variables
  - some linting is added to xml (checking of elements parity)

src/cfg_file.h
src/cfg_file.l
src/cfg_utils.c
src/cfg_xml.c
src/cfg_xml.h
src/main.c

index b4f5a0e1fb0547487ffc342acc311e77fb2de025..3ec7391e43098e8427bc488178c57b14f485eeda 100644 (file)
@@ -266,16 +266,18 @@ struct config_file {
        GHashTable* factors;                                                    /**< hash of factors indexed by symbol name                             */
        GHashTable* c_modules;                                                  /**< hash of c modules indexed by module name                   */
        GHashTable* composite_symbols;                                  /**< hash of composite symbols indexed by its name              */
-    GList *classifiers;                             /**< list of all classifiers defined                    */
-    GList *statfiles;                               /**< list of all statfiles in config file order         */
-    GHashTable *classifiers_symbols;                /**< hashtable indexed by symbol name of classifiers    */
-    GHashTable* cfg_params;                                                    /**< all cfg params indexed by its name in this structure */
+       GList *classifiers;                             /**< list of all classifiers defined                    */
+       GList *statfiles;                               /**< list of all statfiles in config file order         */
+       GHashTable *classifiers_symbols;                /**< hashtable indexed by symbol name of classifiers    */
+       GHashTable* cfg_params;                                                 /**< all cfg params indexed by its name in this structure */
        int clock_res;                                                                  /**< resolution of clock used                                                   */
        double grow_factor;                                                             /**< grow factor for consolidation callback                             */
        GList *views;                                                                   /**< views                                                                                              */
-    GHashTable* domain_settings;                    /**< settings per-domains                               */
-    GHashTable* user_settings;                      /**< settings per-user                                  */
-
+       GHashTable* domain_settings;                    /**< settings per-domains                               */
+       GHashTable* user_settings;                      /**< settings per-user                                  */
+       
+       gchar* checksum;                                                                /**< real checksum of config file                                               */ 
+       gchar* dump_checksum;                                                   /**< dump checksum of config file                                               */ 
 };
 
 /**
@@ -361,6 +363,12 @@ gchar* substitute_variable (struct config_file *cfg, gchar *name, gchar *str, gu
  */
 void post_load_config (struct config_file *cfg);
 
+/**
+ * Calculate checksum for config file
+ * @param cfg config file
+ */
+gboolean get_config_checksum (struct config_file *cfg);
+
 
 /**
  * Replace all \" with a single " in given string
index fd83be66c15f2ebb9f3829c8989690d07106f0fe..83c35290ccdc38dedc85c7881521cbdac891679b 100644 (file)
@@ -163,7 +163,6 @@ yes|YES|no|NO|[yY]|[nN]                     yylval.flag=parse_flag(yytext); return FLAG;
                if ( --include_stack_ptr < 0 ) {
                        include_stack_ptr = 0;
                        yylineno = 1;
-                       post_load_config (cfg);
                        yyterminate ();
                }
                else {
index d2f75e11c21004112215289e4ae42c14da28d511..18677a1caa81c64edb9022a1b6ac48b8cdd8bd72 100644 (file)
@@ -230,6 +230,9 @@ free_config (struct config_file *cfg)
        g_hash_table_remove_all (cfg->cfg_params);
        g_hash_table_unref (cfg->cfg_params);
        g_hash_table_destroy (cfg->classifiers_symbols);
+       if (cfg->checksum) {
+               g_free (cfg->checksum);
+       }
        g_list_free (cfg->classifiers);
        g_list_free (cfg->metrics_list);
        memory_pool_delete (cfg->cfg_pool);
@@ -499,6 +502,37 @@ fill_cfg_params (struct config_file *cfg)
 
 }
 
+gboolean
+get_config_checksum (struct config_file *cfg) 
+{
+       int                             fd;
+       void                           *map;
+       struct stat                     st;
+
+       /* Compute checksum for config file that should be used by xml dumper */
+       if ((fd = open (cfg->cfg_name, O_RDONLY)) == -1) {
+               msg_err ("config file %s is no longer available, cannot calculate checksum");
+               return FALSE;
+       }
+       if (stat (cfg->cfg_name, &st) == -1) {
+               msg_err ("cannot stat %s: %s", cfg->cfg_name, strerror (errno));
+               return FALSE;
+       }
+
+       /* Now mmap this file to simplify reading process */
+       if ((map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+               msg_err ("cannot mmap %s: %s", cfg->cfg_name, strerror (errno));
+               close (fd);
+               return FALSE;
+       }
+       close (fd);
+       
+       /* Get checksum for a file */
+       cfg->checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, map, st.st_size);
+       munmap (map, st.st_size);
+       
+       return TRUE;
+}
 /* 
  * Perform post load actions
  */
@@ -539,7 +573,7 @@ post_load_config (struct config_file *cfg)
                cfg->metrics_list = g_list_prepend (cfg->metrics_list, def_metric);
                g_hash_table_insert (cfg->metrics, DEFAULT_METRIC, def_metric);
        }
-
+       
 }
 
 
index 93c8a57854e0f719cb787699024384c6f310bc77..aa9ccf2fecee60dd2a3fe6a2dff31817834549f0 100644 (file)
@@ -80,6 +80,24 @@ static struct xml_parser_rule grammar[] = {
                                G_STRUCT_OFFSET (struct config_file, pid_file),
                                NULL
                        },
+                       {
+                               "raw_mode",
+                               xml_handle_boolean,
+                               G_STRUCT_OFFSET (struct config_file, raw_mode),
+                               NULL
+                       },
+                       {
+                               "tempdir",
+                               xml_handle_string,
+                               G_STRUCT_OFFSET (struct config_file, temp_dir),
+                               NULL
+                       },
+                       {
+                               "checksum",
+                               xml_handle_string,
+                               G_STRUCT_OFFSET (struct config_file, dump_checksum),
+                               NULL
+                       },
                        {
                                "statfile_pool_size",
                                xml_handle_size,
@@ -718,7 +736,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
                        if (g_ascii_strcasecmp (element_name, "module") == 0) {
                                /* Read module data */
                                if (extract_attr ("name", attribute_names, attribute_values, &res)) {
-                                       g_strlcpy (ud->section_name, res, sizeof (res));
+                                       g_strlcpy (ud->section_name, res, sizeof (ud->section_name));
                                        ud->state = XML_READ_MODULE;
                                }
                                else {
@@ -734,7 +752,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
                        }
                        else if (g_ascii_strcasecmp (element_name, "metric") == 0) {
                                if (extract_attr ("name", attribute_names, attribute_values, &res)) {
-                                       g_strlcpy (ud->section_name, res, sizeof (res));
+                                       g_strlcpy (ud->section_name, res, sizeof (ud->section_name));
                                        ud->state = XML_READ_METRIC;
                                        /* Create object */
                                        ud->other_data = memory_pool_alloc0 (ud->cfg->cfg_pool, sizeof (struct metric));
@@ -746,7 +764,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
                        }
                        else if (g_ascii_strcasecmp (element_name, "classifier") == 0) {
                                if (extract_attr ("type", attribute_names, attribute_values, &res)) {
-                                       g_strlcpy (ud->section_name, res, sizeof (res));
+                                       g_strlcpy (ud->section_name, res, sizeof (ud->section_name));
                                        ud->state = XML_READ_CLASSIFIER;
                                        /* Create object */
                                        ud->other_data = check_classifier_cfg (ud->cfg, NULL);
@@ -761,25 +779,21 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
                                /* Create object */
                                ud->other_data = check_worker_conf (ud->cfg, NULL);
                        }
-                       else {
-                               /* Other params */
-                               if (g_ascii_strcasecmp (element_name, "variable") == 0) {
-                                       if (extract_attr ("name", attribute_names, attribute_values, &res)) {
-                                               g_strlcpy (ud->section_name, res, sizeof (res));
-                                               ud->state = XML_READ_VARIABLE;
-                                       }
-                                       else {
-                                               *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'variable'");
-                                               ud->state = XML_ERROR;
-                                       }
-                               
-                               } 
-                               else if (g_ascii_strcasecmp (element_name, "pidfile") == 0) {
-                                       ud->state = XML_READ_PIDFILE;
+                       else if (g_ascii_strcasecmp (element_name, "variable") == 0) {
+                               if (extract_attr ("name", attribute_names, attribute_values, &res)) {
+                                       g_strlcpy (ud->section_name, res, sizeof (ud->section_name));
+                                       ud->state = XML_READ_VARIABLE;
                                }
-                               else if (g_ascii_strcasecmp (element_name, "filters") == 0) {
-                                       ud->state = XML_READ_FILTERS;
+                               else {
+                                       *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'variable'");
+                                       ud->state = XML_ERROR;
                                }
+                               
+                       } 
+                       else {
+                               /* Extract other tags */
+                               g_strlcpy (ud->section_name, element_name, sizeof (ud->section_name));
+                               ud->state = XML_READ_VALUE;
                        }
                        break;
                case XML_READ_MODULE:
@@ -857,14 +871,9 @@ rspamd_xml_end_element (GMarkupParseContext        *context, const gchar *element_name,
                case XML_READ_VARIABLE:
                        CHECK_TAG ("variable", TRUE);
                        break;
-               case XML_READ_PIDFILE:
-                       CHECK_TAG ("pidfile", TRUE);
-                       break;
-               case XML_READ_STATFILE_POOL:
-                       CHECK_TAG ("statfile_pool_size", TRUE);
-                       break;
-               case XML_READ_FILTERS:
-                       CHECK_TAG ("filters", TRUE);
+               case XML_READ_VALUE:
+                       /* Check tags parity */
+                       CHECK_TAG (ud->section_name, TRUE);
                        break;
                case XML_READ_LOGGING:
                        CHECK_TAG ("logging", FALSE);
@@ -930,9 +939,7 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len
                        }
                        break;
                case XML_READ_VARIABLE:
-               case XML_READ_PIDFILE:
-               case XML_READ_STATFILE_POOL:
-               case XML_READ_FILTERS:
+               case XML_READ_VALUE:
                        if (!call_param_handler (ud, ud->section_name, val, cfg, XML_SECTION_MAIN)) {
                                *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val);
                                ud->state = XML_ERROR;
@@ -944,8 +951,6 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len
                                ud->state = XML_ERROR;
                        }
                        break;
-               case XML_READ_PARAM:
-                       break;
                default:
                        ud->state = XML_ERROR;
                        break;
@@ -961,3 +966,211 @@ rspamd_xml_error (GMarkupParseContext *context, GError *error, gpointer user_dat
        msg_err ("xml parser error: %s, at state %d", error->message, ud->state);
 }
 
+
+/* Dumper part */
+
+/* Dump specific sections */
+
+/* Dump main section variables */
+static gboolean
+xml_dump_main (struct config_file *cfg, FILE *f)
+{
+       char *escaped_str;
+       
+       /* Print header comment */
+       fprintf (f, "<!-- Main section -->" CRLF);
+
+       escaped_str = g_markup_escape_text (cfg->temp_dir, -1); 
+       fprintf (f, "  <tempdir>%s</tempdir>" CRLF, escaped_str);
+       g_free (escaped_str);
+
+       escaped_str = g_markup_escape_text (cfg->pid_file, -1); 
+       fprintf (f, "  <pidfile>%s</pidfile>" CRLF, escaped_str);
+       g_free (escaped_str);
+
+       escaped_str = g_markup_escape_text (cfg->filters_str, -1); 
+       fprintf (f, "  <filters>%s</filters>" CRLF, escaped_str);
+       g_free (escaped_str);
+
+       if (cfg->checksum)  {
+               escaped_str = g_markup_escape_text (cfg->checksum, -1); 
+               fprintf (f, "  <checksum>%s</checksum>" CRLF, escaped_str);
+               g_free (escaped_str);
+       }
+
+       fprintf (f, "  <raw_mode>%s</raw_mode>" CRLF, cfg->raw_mode ? "yes" : "no");
+
+       /* Print footer comment */
+       fprintf (f, "<!-- End of main section -->" CRLF);
+
+       return TRUE;
+}
+
+/* Dump variables section */
+static void
+xml_variable_callback (gpointer key, gpointer value, gpointer user_data)
+{
+       FILE *f = user_data;
+       char *escaped_key, *escaped_value;
+
+       escaped_key = g_markup_escape_text (key, -1); 
+       escaped_value = g_markup_escape_text (value, -1);
+       fprintf (f,  "  <variable name=\"%s\">%s</variable>" CRLF, escaped_key, escaped_value);
+       g_free (escaped_key);
+       g_free (escaped_value);
+}
+
+static gboolean
+xml_dump_variables (struct config_file *cfg, FILE *f)
+{
+       /* Print header comment */
+       fprintf (f, "<!-- Variables section -->" CRLF);
+
+       /* Iterate through variables */
+       g_hash_table_foreach (cfg->variables, xml_variable_callback, (gpointer)f);
+
+       /* Print footer comment */
+       fprintf (f, "<!-- End of variables section -->" CRLF);
+
+       return TRUE;
+}
+
+/* Workers */
+static void
+xml_worker_param_callback (gpointer key, gpointer value, gpointer user_data)
+{
+       FILE *f = user_data;
+       char *escaped_key, *escaped_value;
+
+       escaped_key = g_markup_escape_text (key, -1); 
+       escaped_value = g_markup_escape_text (value, -1);
+       fprintf (f,  "    <param name=\"%s\">%s</param>" CRLF, escaped_key, escaped_value);
+       g_free (escaped_key);
+       g_free (escaped_value);
+}
+
+static gboolean
+xml_dump_workers (struct config_file *cfg, FILE *f)
+{
+       GList *cur;
+       struct worker_conf *wrk;
+       char *escaped_str;
+
+       /* Print header comment */
+       fprintf (f, "<!-- Workers section -->" CRLF);
+
+       /* Iterate through list */
+       cur = g_list_first (cfg->workers);
+       while (cur) {
+               wrk = cur->data;
+               
+               fprintf (f, "<worker>" CRLF);
+               switch (wrk->type) {
+                       case TYPE_WORKER:
+                               fprintf (f, "  <type>normal</type>" CRLF);
+                               break;
+                       case TYPE_CONTROLLER:
+                               fprintf (f, "  <type>controller</type>" CRLF);
+                               break;
+                       case TYPE_FUZZY:
+                               fprintf (f, "  <type>fuzzy</type>" CRLF);
+                               break;
+                       case TYPE_LMTP:
+                               fprintf (f, "  <type>lmtp</type>" CRLF);
+                               break;
+               }
+               escaped_str = g_markup_escape_text (wrk->bind_host, -1); 
+               fprintf (f, "  <bind_socket>%s</bind_socket>" CRLF, escaped_str);
+               g_free (escaped_str);
+
+               fprintf (f, "  <count>%u</count>" CRLF, wrk->count);
+               fprintf (f, "  <maxfiles>%u</maxfiles>" CRLF, wrk->rlimit_nofile);
+               fprintf (f, "  <maxcore>%u</maxcore>" CRLF, wrk->rlimit_maxcore);
+               
+               /* Now dump other attrs */
+               fprintf (f, "<!-- Other params -->" CRLF);
+               g_hash_table_foreach (wrk->params, xml_worker_param_callback, f);
+
+               fprintf (f, "</worker>" CRLF);
+
+               cur = g_list_next (cur);
+       }
+
+       /* Print footer comment */
+       fprintf (f, "<!-- End of workers section -->" CRLF);
+
+       return TRUE;
+}
+
+/* Modules dump */
+static void
+xml_module_callback (gpointer key, gpointer value, gpointer user_data)
+{
+       FILE *f = user_data;
+       char *escaped_key, *escaped_value;
+       GList *cur;
+       struct module_opt *opt;
+       
+       escaped_key = g_markup_escape_text (key, -1); 
+       fprintf (f, "<!-- %s -->" CRLF, escaped_key);
+       fprintf (f, "<module name=\"%s\">" CRLF, escaped_key);
+       g_free (escaped_key);
+
+       cur = g_list_first (value);
+       while (cur) {
+               opt = cur->data;
+               escaped_key = g_markup_escape_text (opt->param, -1); 
+               escaped_value = g_markup_escape_text (opt->value, -1);
+               fprintf (f,  "  <option name=\"%s\">%s</option>" CRLF, escaped_key, escaped_value);
+               g_free (escaped_key);
+               g_free (escaped_value);
+               cur = g_list_next (cur);
+       }
+       fprintf (f, "</module>" CRLF);
+}
+
+static gboolean
+xml_dump_modules (struct config_file *cfg, FILE *f)
+{
+       /* Print header comment */
+       fprintf (f, "<!-- Modules section -->" CRLF);
+
+       /* Iterate through variables */
+       g_hash_table_foreach (cfg->modules_opts, xml_module_callback, (gpointer)f);
+
+       /* Print footer comment */
+       fprintf (f, "<!-- End of modules section -->" CRLF);
+
+       return TRUE;
+}
+
+#define CHECK_RES do { if (!res) { fclose (f); return FALSE; } } while (0)
+gboolean 
+xml_dump_config (struct config_file *cfg, const char *filename)
+{
+       FILE *f;
+       gboolean res = FALSE;
+
+       f = fopen (filename, "w");
+       if (f == NULL) {
+               msg_err ("cannot open file '%s': %s", filename, strerror (errno));
+               return FALSE;
+       }
+       
+       /* Header */
+       fprintf (f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" CRLF "<rspamd>" CRLF);
+       /* Now dump all parts of config */
+       res = xml_dump_main (cfg, f);
+       CHECK_RES;
+       res = xml_dump_variables (cfg, f);
+       CHECK_RES;
+       res = xml_dump_workers (cfg, f);
+       CHECK_RES;
+       res = xml_dump_modules (cfg, f);
+       CHECK_RES;
+       /* Footer */
+       fprintf (f, "</rspamd>" CRLF);
+       fclose (f);
+
+       return TRUE;
+}
index 513cf0f03076cfa515e91b8a428fb5fdd40734e5..38c86c3d6a324101319e17c15f5d3d05326463cd 100644 (file)
@@ -21,11 +21,9 @@ enum xml_read_state {
        XML_READ_METRIC,
        XML_READ_WORKER,
        XML_READ_VARIABLE,
-       XML_READ_PIDFILE,
-       XML_READ_STATFILE_POOL,
-       XML_READ_FILTERS,
        XML_READ_LOGGING,
        XML_ERROR,
+       XML_READ_VALUE,
        XML_END
 };
 
@@ -40,6 +38,8 @@ struct rspamd_xml_userdata {
 /* Text is NULL terminated here */
 typedef gboolean (*element_handler_func) (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
 
+/* Callbacks */
+
 /* Called for open tags <foo bar="baz"> */
 void rspamd_xml_start_element (GMarkupParseContext     *context,
                                                                const gchar         *element_name,
@@ -92,4 +92,9 @@ gboolean handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx
 gboolean handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
 gboolean handle_log_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
 gboolean handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
+
+/* Dumper functions */
+gboolean xml_dump_config (struct config_file *cfg, const char *filename);
+
 #endif
index fd250781dbcf8370a9c3a23400f981f34a846a5f..350199632c07f201c9bfc49b5bae0ea713d88ceb 100644 (file)
@@ -638,6 +638,12 @@ main (int argc, char **argv, char **env)
        }
 
        fclose (f);
+       /* Dump it to xml */
+       if (get_config_checksum (rspamd->cfg)) {
+               xml_dump_config (rspamd->cfg, "/tmp/rspamd.xml");
+       }
+       /* Do post-load actions */
+       post_load_config (rspamd->cfg);
        /* Init counters */
        counters = rspamd_hash_new_shared (rspamd->server_pool, g_str_hash, g_str_equal, 64);