Merge pull request #3339 from jkohen/patch-1
[collectd.git] / src / filter_chain.c
diff --git a/src/filter_chain.c b/src/filter_chain.c
deleted file mode 100644 (file)
index e25e7a0..0000000
+++ /dev/null
@@ -1,1055 +0,0 @@
-/**
- * collectd - src/filter_chain.h
- * Copyright (C) 2008-2010  Florian octo Forster
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; only version 2 of the License is applicable.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * Authors:
- *   Florian octo Forster <octo at verplant.org>
- **/
-
-#include "collectd.h"
-#include "configfile.h"
-#include "plugin.h"
-#include "utils_complain.h"
-#include "common.h"
-#include "filter_chain.h"
-
-/*
- * Data types
- */
-/* List of matches, used in fc_rule_t and for the global `match_list_head'
- * variable. */
-struct fc_match_s;
-typedef struct fc_match_s fc_match_t; /* {{{ */
-struct fc_match_s
-{
-  char name[DATA_MAX_NAME_LEN];
-  match_proc_t proc;
-  void *user_data;
-  fc_match_t *next;
-}; /* }}} */
-
-/* List of targets, used in fc_rule_t and for the global `target_list_head'
- * variable. */
-struct fc_target_s;
-typedef struct fc_target_s fc_target_t; /* {{{ */
-struct fc_target_s
-{
-  char name[DATA_MAX_NAME_LEN];
-  void *user_data;
-  target_proc_t proc;
-  fc_target_t *next;
-}; /* }}} */
-
-/* List of rules, used in fc_chain_t */
-struct fc_rule_s;
-typedef struct fc_rule_s fc_rule_t; /* {{{ */
-struct fc_rule_s
-{
-  char name[DATA_MAX_NAME_LEN];
-  fc_match_t  *matches;
-  fc_target_t *targets;
-  fc_rule_t *next;
-}; /* }}} */
-
-/* List of chains, used for `chain_list_head' */
-struct fc_chain_s /* {{{ */
-{
-  char name[DATA_MAX_NAME_LEN];
-  fc_rule_t   *rules;
-  fc_target_t *targets;
-  fc_chain_t  *next;
-}; /* }}} */
-
-/* Writer configuration. */
-struct fc_writer_s;
-typedef struct fc_writer_s fc_writer_t; /* {{{ */
-struct fc_writer_s
-{
-  char *plugin;
-  c_complain_t complaint;
-}; /* }}} */
-
-/*
- * Global variables
- */
-static fc_match_t  *match_list_head;
-static fc_target_t *target_list_head;
-static fc_chain_t  *chain_list_head;
-
-/*
- * Private functions
- */
-static void fc_free_matches (fc_match_t *m) /* {{{ */
-{
-  if (m == NULL)
-    return;
-
-  if (m->proc.destroy != NULL)
-    (*m->proc.destroy) (&m->user_data);
-  else if (m->user_data != NULL)
-  {
-    ERROR ("Filter subsystem: fc_free_matches: There is user data, but no "
-        "destroy functions has been specified. "
-        "Memory will probably be lost!");
-  }
-
-  if (m->next != NULL)
-    fc_free_matches (m->next);
-
-  free (m);
-} /* }}} void fc_free_matches */
-
-static void fc_free_targets (fc_target_t *t) /* {{{ */
-{
-  if (t == NULL)
-    return;
-
-  if (t->proc.destroy != NULL)
-    (*t->proc.destroy) (&t->user_data);
-  else if (t->user_data != NULL)
-  {
-    ERROR ("Filter subsystem: fc_free_targets: There is user data, but no "
-        "destroy functions has been specified. "
-        "Memory will probably be lost!");
-  }
-
-  if (t->next != NULL)
-    fc_free_targets (t->next);
-
-  free (t);
-} /* }}} void fc_free_targets */
-
-static void fc_free_rules (fc_rule_t *r) /* {{{ */
-{
-  if (r == NULL)
-    return;
-
-  fc_free_matches (r->matches);
-  fc_free_targets (r->targets);
-
-  if (r->next != NULL)
-    fc_free_rules (r->next);
-
-  free (r);
-} /* }}} void fc_free_rules */
-
-static void fc_free_chains (fc_chain_t *c) /* {{{ */
-{
-  if (c == NULL)
-    return;
-
-  fc_free_rules (c->rules);
-  fc_free_targets (c->targets);
-
-  if (c->next != NULL)
-    fc_free_chains (c->next);
-
-  free (c);
-} /* }}} void fc_free_chains */
-
-static char *fc_strdup (const char *orig) /* {{{ */
-{
-  size_t sz;
-  char *dest;
-
-  if (orig == NULL)
-    return (NULL);
-
-  sz = strlen (orig) + 1;
-  dest = (char *) malloc (sz);
-  if (dest == NULL)
-    return (NULL);
-
-  memcpy (dest, orig, sz);
-
-  return (dest);
-} /* }}} char *fc_strdup */
-
-/*
- * Configuration.
- *
- * The configuration looks somewhat like this:
- *
- *  <Chain "PreCache">
- *    <Rule>
- *      <Match "regex">
- *        Plugin "^mysql$"
- *        Type "^mysql_command$"
- *        TypeInstance "^show_"
- *      </Match>
- *      <Target "drop">
- *      </Target>
- *    </Rule>
- *
- *    <Target "write">
- *      Plugin "rrdtool"
- *    </Target>
- *  </Chain>
- */
-static int fc_config_add_match (fc_match_t **matches_head, /* {{{ */
-    oconfig_item_t *ci)
-{
-  fc_match_t *m;
-  fc_match_t *ptr;
-  int status;
-
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("Filter subsystem: `Match' blocks require "
-        "exactly one string argument.");
-    return (-1);
-  }
-
-  ptr = match_list_head;
-  while (ptr != NULL)
-  {
-    if (strcasecmp (ptr->name, ci->values[0].value.string) == 0)
-      break;
-    ptr = ptr->next;
-  }
-
-  if (ptr == NULL)
-  {
-    WARNING ("Filter subsystem: Cannot find a \"%s\" match. "
-        "Did you load the appropriate plugin?",
-        ci->values[0].value.string);
-    return (-1);
-  }
-
-  m = (fc_match_t *) malloc (sizeof (*m));
-  if (m == NULL)
-  {
-    ERROR ("fc_config_add_match: malloc failed.");
-    return (-1);
-  }
-  memset (m, 0, sizeof (*m));
-
-  sstrncpy (m->name, ptr->name, sizeof (m->name));
-  memcpy (&m->proc, &ptr->proc, sizeof (m->proc));
-  m->user_data = NULL;
-  m->next = NULL;
-
-  if (m->proc.create != NULL)
-  {
-    status = (*m->proc.create) (ci, &m->user_data);
-    if (status != 0)
-    {
-      WARNING ("Filter subsystem: Failed to create a %s match.",
-          m->name);
-      fc_free_matches (m);
-      return (-1);
-    }
-  }
-
-  if (*matches_head != NULL)
-  {
-    ptr = *matches_head;
-    while (ptr->next != NULL)
-      ptr = ptr->next;
-
-    ptr->next = m;
-  }
-  else
-  {
-    *matches_head = m;
-  }
-
-  return (0);
-} /* }}} int fc_config_add_match */
-
-static int fc_config_add_target (fc_target_t **targets_head, /* {{{ */
-    oconfig_item_t *ci)
-{
-  fc_target_t *t;
-  fc_target_t *ptr;
-  int status;
-
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("Filter subsystem: `Target' blocks require "
-        "exactly one string argument.");
-    return (-1);
-  }
-
-  ptr = target_list_head;
-  while (ptr != NULL)
-  {
-    if (strcasecmp (ptr->name, ci->values[0].value.string) == 0)
-      break;
-    ptr = ptr->next;
-  }
-
-  if (ptr == NULL)
-  {
-    WARNING ("Filter subsystem: Cannot find a \"%s\" target. "
-        "Did you load the appropriate plugin?",
-        ci->values[0].value.string);
-    return (-1);
-  }
-
-  t = (fc_target_t *) malloc (sizeof (*t));
-  if (t == NULL)
-  {
-    ERROR ("fc_config_add_target: malloc failed.");
-    return (-1);
-  }
-  memset (t, 0, sizeof (*t));
-
-  sstrncpy (t->name, ptr->name, sizeof (t->name));
-  memcpy (&t->proc, &ptr->proc, sizeof (t->proc));
-  t->user_data = NULL;
-  t->next = NULL;
-
-  if (t->proc.create != NULL)
-  {
-    status = (*t->proc.create) (ci, &t->user_data);
-    if (status != 0)
-    {
-      WARNING ("Filter subsystem: Failed to create a %s target.",
-          t->name);
-      fc_free_targets (t);
-      return (-1);
-    }
-  }
-  else
-  {
-    t->user_data = NULL;
-  }
-  
-  if (*targets_head != NULL)
-  {
-    ptr = *targets_head;
-    while (ptr->next != NULL)
-      ptr = ptr->next;
-
-    ptr->next = t;
-  }
-  else
-  {
-    *targets_head = t;
-  }
-
-  return (0);
-} /* }}} int fc_config_add_target */
-
-static int fc_config_add_rule (fc_chain_t *chain, /* {{{ */
-    oconfig_item_t *ci)
-{
-  fc_rule_t *rule;
-  char rule_name[2*DATA_MAX_NAME_LEN] = "Unnamed rule";
-  int status = 0;
-  int i;
-
-  if (ci->values_num > 1)
-  {
-    WARNING ("Filter subsystem: `Rule' blocks have at most one argument.");
-    return (-1);
-  }
-  else if ((ci->values_num == 1)
-      && (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("Filter subsystem: `Rule' blocks expect one string argument "
-        "or no argument at all.");
-    return (-1);
-  }
-
-  rule = (fc_rule_t *) malloc (sizeof (*rule));
-  if (rule == NULL)
-  {
-    ERROR ("fc_config_add_rule: malloc failed.");
-    return (-1);
-  }
-  memset (rule, 0, sizeof (*rule));
-  rule->next = NULL;
-
-  if (ci->values_num == 1)
-  {
-    sstrncpy (rule->name, ci->values[0].value.string, sizeof (rule->name));
-    ssnprintf (rule_name, sizeof (rule_name), "Rule \"%s\"",
-        ci->values[0].value.string);
-  }
-
-  for (i = 0; i < ci->children_num; i++)
-  {
-    oconfig_item_t *option = ci->children + i;
-
-    if (strcasecmp ("Match", option->key) == 0)
-      status = fc_config_add_match (&rule->matches, option);
-    else if (strcasecmp ("Target", option->key) == 0)
-      status = fc_config_add_target (&rule->targets, option);
-    else
-    {
-      WARNING ("Filter subsystem: %s: Option `%s' not allowed "
-          "inside a <Rule> block.", rule_name, option->key);
-      status = -1;
-    }
-
-    if (status != 0)
-      break;
-  } /* for (ci->children) */
-
-  /* Additional sanity checking. */
-  while (status == 0)
-  {
-    if (rule->targets == NULL)
-    {
-      WARNING ("Filter subsystem: %s: No target has been specified.",
-          rule_name);
-      status = -1;
-      break;
-    }
-
-    break;
-  } /* while (status == 0) */
-
-  if (status != 0)
-  {
-    fc_free_rules (rule);
-    return (-1);
-  }
-
-  if (chain->rules != NULL)
-  {
-    fc_rule_t *ptr;
-
-    ptr = chain->rules;
-    while (ptr->next != NULL)
-      ptr = ptr->next;
-
-    ptr->next = rule;
-  }
-  else
-  {
-    chain->rules = rule;
-  }
-
-  return (0);
-} /* }}} int fc_config_add_rule */
-
-static int fc_config_add_chain (const oconfig_item_t *ci) /* {{{ */
-{
-  fc_chain_t *chain;
-  int status = 0;
-  int i;
-
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("Filter subsystem: <Chain> blocks require exactly one "
-        "string argument.");
-    return (-1);
-  }
-
-  chain = (fc_chain_t *) malloc (sizeof (*chain));
-  if (chain == NULL)
-  {
-    ERROR ("fc_config_add_chain: malloc failed.");
-    return (-1);
-  }
-  memset (chain, 0, sizeof (*chain));
-  sstrncpy (chain->name, ci->values[0].value.string, sizeof (chain->name));
-  chain->rules = NULL;
-  chain->targets = NULL;
-  chain->next = NULL;
-
-  for (i = 0; i < ci->children_num; i++)
-  {
-    oconfig_item_t *option = ci->children + i;
-
-    if (strcasecmp ("Rule", option->key) == 0)
-      status = fc_config_add_rule (chain, option);
-    else if (strcasecmp ("Target", option->key) == 0)
-      status = fc_config_add_target (&chain->targets, option);
-    else
-    {
-      WARNING ("Filter subsystem: Chain %s: Option `%s' not allowed "
-          "inside a <Chain> block.", chain->name, option->key);
-      status = -1;
-    }
-
-    if (status != 0)
-      break;
-  } /* for (ci->children) */
-
-  if (status != 0)
-  {
-    fc_free_chains (chain);
-    return (-1);
-  }
-
-  if (chain_list_head != NULL)
-  {
-    fc_chain_t *ptr;
-
-    ptr = chain_list_head;
-    while (ptr->next != NULL)
-      ptr = ptr->next;
-
-    ptr->next = chain;
-  }
-  else
-  {
-    chain_list_head = chain;
-  }
-
-  return (0);
-} /* }}} int fc_config_add_chain */
-
-/*
- * Built-in target "jump"
- *
- * Prefix `bit' like `_b_uilt-_i_n _t_arget'
- */
-static int fc_bit_jump_create (const oconfig_item_t *ci, /* {{{ */
-    void **user_data)
-{
-  oconfig_item_t *ci_chain;
-
-  if (ci->children_num != 1)
-  {
-    ERROR ("Filter subsystem: The built-in target `jump' needs exactly "
-        "one `Chain' argument!");
-    return (-1);
-  }
-
-  ci_chain = ci->children;
-  if (strcasecmp ("Chain", ci_chain->key) != 0)
-  {
-    ERROR ("Filter subsystem: The built-in target `jump' does not "
-        "support the configuration option `%s'.",
-        ci_chain->key);
-    return (-1);
-  }
-
-  if ((ci_chain->values_num != 1)
-      || (ci_chain->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    ERROR ("Filter subsystem: Built-in target `jump': The `Chain' option "
-        "needs exactly one string argument.");
-    return (-1);
-  }
-
-  *user_data = fc_strdup (ci_chain->values[0].value.string);
-  if (*user_data == NULL)
-  {
-    ERROR ("fc_bit_jump_create: fc_strdup failed.");
-    return (-1);
-  }
-
-  return (0);
-} /* }}} int fc_bit_jump_create */
-
-static int fc_bit_jump_destroy (void **user_data) /* {{{ */
-{
-  if (user_data != NULL)
-  {
-    free (*user_data);
-    *user_data = NULL;
-  }
-
-  return (0);
-} /* }}} int fc_bit_jump_destroy */
-
-static int fc_bit_jump_invoke (const data_set_t *ds, /* {{{ */
-    value_list_t *vl, notification_meta_t __attribute__((unused)) **meta,
-    void **user_data)
-{
-  char *chain_name;
-  fc_chain_t *chain;
-  int status;
-
-  chain_name = *user_data;
-
-  for (chain = chain_list_head; chain != NULL; chain = chain->next)
-    if (strcasecmp (chain_name, chain->name) == 0)
-      break;
-
-  if (chain == NULL)
-  {
-    ERROR ("Filter subsystem: Built-in target `jump': There is no chain "
-        "named `%s'.", chain_name);
-    return (-1);
-  }
-
-  status = fc_process_chain (ds, vl, chain);
-  if (status < 0)
-    return (status);
-  else if (status == FC_TARGET_STOP)
-    return (FC_TARGET_STOP);
-  else
-    return (FC_TARGET_CONTINUE);
-} /* }}} int fc_bit_jump_invoke */
-
-static int fc_bit_stop_invoke (const data_set_t __attribute__((unused)) *ds, /* {{{ */
-    value_list_t __attribute__((unused)) *vl,
-    notification_meta_t __attribute__((unused)) **meta,
-    void __attribute__((unused)) **user_data)
-{
-  return (FC_TARGET_STOP);
-} /* }}} int fc_bit_stop_invoke */
-
-static int fc_bit_return_invoke (const data_set_t __attribute__((unused)) *ds, /* {{{ */
-    value_list_t __attribute__((unused)) *vl,
-    notification_meta_t __attribute__((unused)) **meta,
-    void __attribute__((unused)) **user_data)
-{
-  return (FC_TARGET_RETURN);
-} /* }}} int fc_bit_return_invoke */
-
-static int fc_bit_write_create (const oconfig_item_t *ci, /* {{{ */
-    void **user_data)
-{
-  int i;
-
-  fc_writer_t *plugin_list = NULL;
-  size_t plugin_list_len = 0;
-
-  for (i = 0; i < ci->children_num; i++)
-  {
-    oconfig_item_t *child = ci->children + i;
-    fc_writer_t *temp;
-    int j;
-
-    if (strcasecmp ("Plugin", child->key) != 0)
-    {
-      ERROR ("Filter subsystem: The built-in target `write' does not "
-          "support the configuration option `%s'.",
-          child->key);
-      continue;
-    }
-
-    for (j = 0; j < child->values_num; j++)
-    {
-      char *plugin;
-
-      if (child->values[j].type != OCONFIG_TYPE_STRING)
-      {
-        ERROR ("Filter subsystem: Built-in target `write': "
-            "The `Plugin' option accepts only string arguments.");
-        continue;
-      }
-      plugin = child->values[j].value.string;
-
-      temp = (fc_writer_t *) realloc (plugin_list, (plugin_list_len + 2)
-          * (sizeof (*plugin_list)));
-      if (temp == NULL)
-      {
-        ERROR ("fc_bit_write_create: realloc failed.");
-        continue;
-      }
-      plugin_list = temp;
-
-      plugin_list[plugin_list_len].plugin = fc_strdup (plugin);
-      if (plugin_list[plugin_list_len].plugin == NULL)
-      {
-        ERROR ("fc_bit_write_create: fc_strdup failed.");
-        continue;
-      }
-      C_COMPLAIN_INIT (&plugin_list[plugin_list_len].complaint);
-      plugin_list_len++;
-      plugin_list[plugin_list_len].plugin = NULL;
-    } /* for (j = 0; j < child->values_num; j++) */
-  } /* for (i = 0; i < ci->children_num; i++) */
-
-  *user_data = plugin_list;
-
-  return (0);
-} /* }}} int fc_bit_write_create */
-
-static int fc_bit_write_destroy (void **user_data) /* {{{ */
-{
-  fc_writer_t *plugin_list;
-  size_t i;
-
-  if ((user_data == NULL) || (*user_data == NULL))
-    return (0);
-
-  plugin_list = *user_data;
-
-  for (i = 0; plugin_list[i].plugin != NULL; i++)
-    free (plugin_list[i].plugin);
-  free (plugin_list);
-
-  return (0);
-} /* }}} int fc_bit_write_destroy */
-
-static int fc_bit_write_invoke (const data_set_t *ds, /* {{{ */
-    value_list_t *vl, notification_meta_t __attribute__((unused)) **meta,
-    void **user_data)
-{
-  fc_writer_t *plugin_list;
-  int status;
-
-  plugin_list = NULL;
-  if (user_data != NULL)
-    plugin_list = *user_data;
-
-  if ((plugin_list == NULL) || (plugin_list[0].plugin == NULL))
-  {
-    static c_complain_t write_complaint = C_COMPLAIN_INIT_STATIC;
-
-    status = plugin_write (/* plugin = */ NULL, ds, vl);
-    if (status == ENOENT)
-    {
-      /* in most cases this is a permanent error, so use the complain
-       * mechanism rather than spamming the logs */
-      c_complain (LOG_INFO, &write_complaint,
-          "Filter subsystem: Built-in target `write': Dispatching value to "
-          "all write plugins failed with status %i (ENOENT). "
-          "Most likely this means you didn't load any write plugins.",
-          status);
-    }
-    else if (status != 0)
-    {
-      /* often, this is a permanent error (e.g. target system unavailable),
-       * so use the complain mechanism rather than spamming the logs */
-      c_complain (LOG_INFO, &write_complaint,
-          "Filter subsystem: Built-in target `write': Dispatching value to "
-          "all write plugins failed with status %i.", status);
-    }
-    else
-    {
-      assert (status == 0);
-      c_release (LOG_INFO, &write_complaint, "Filter subsystem: "
-          "Built-in target `write': Some write plugin is back to normal "
-          "operation. `write' succeeded.");
-    }
-  }
-  else
-  {
-    size_t i;
-
-    for (i = 0; plugin_list[i].plugin != NULL; i++)
-    {
-      status = plugin_write (plugin_list[i].plugin, ds, vl);
-      if (status != 0)
-      {
-        c_complain (LOG_INFO, &plugin_list[i].complaint,
-            "Filter subsystem: Built-in target `write': Dispatching value to "
-            "the `%s' plugin failed with status %i.",
-            plugin_list[i].plugin, status);
-      }
-      else
-      {
-        c_release (LOG_INFO, &plugin_list[i].complaint,
-            "Filter subsystem: Built-in target `write': Plugin `%s' is back "
-            "to normal operation. `write' succeeded.", plugin_list[i].plugin);
-      }
-    } /* for (i = 0; plugin_list[i] != NULL; i++) */
-  }
-
-  return (FC_TARGET_CONTINUE);
-} /* }}} int fc_bit_write_invoke */
-
-static int fc_init_once (void) /* {{{ */
-{
-  static int done = 0;
-  target_proc_t tproc;
-
-  if (done != 0)
-    return (0);
-
-  memset (&tproc, 0, sizeof (tproc));
-  tproc.create  = fc_bit_jump_create;
-  tproc.destroy = fc_bit_jump_destroy;
-  tproc.invoke  = fc_bit_jump_invoke;
-  fc_register_target ("jump", tproc);
-
-  memset (&tproc, 0, sizeof (tproc));
-  tproc.create  = NULL;
-  tproc.destroy = NULL;
-  tproc.invoke  = fc_bit_stop_invoke;
-  fc_register_target ("stop", tproc);
-
-  memset (&tproc, 0, sizeof (tproc));
-  tproc.create  = NULL;
-  tproc.destroy = NULL;
-  tproc.invoke  = fc_bit_return_invoke;
-  fc_register_target ("return", tproc);
-
-  memset (&tproc, 0, sizeof (tproc));
-  tproc.create  = fc_bit_write_create;
-  tproc.destroy = fc_bit_write_destroy;
-  tproc.invoke  = fc_bit_write_invoke;
-  fc_register_target ("write", tproc);
-
-  done++;
-  return (0);
-} /* }}} int fc_init_once */
-
-/*
- * Public functions
- */
-/* Add a match to list of available matches. */
-int fc_register_match (const char *name, match_proc_t proc) /* {{{ */
-{
-  fc_match_t *m;
-
-  DEBUG ("fc_register_match (%s);", name);
-
-  m = (fc_match_t *) malloc (sizeof (*m));
-  if (m == NULL)
-    return (-ENOMEM);
-  memset (m, 0, sizeof (*m));
-
-  sstrncpy (m->name, name, sizeof (m->name));
-  memcpy (&m->proc, &proc, sizeof (m->proc));
-  m->next = NULL;
-
-  if (match_list_head == NULL)
-  {
-    match_list_head = m;
-  }
-  else
-  {
-    fc_match_t *ptr;
-
-    ptr = match_list_head;
-    while (ptr->next != NULL)
-      ptr = ptr->next;
-
-    ptr->next = m;
-  }
-
-  return (0);
-} /* }}} int fc_register_match */
-
-/* Add a target to list of available targets. */
-int fc_register_target (const char *name, target_proc_t proc) /* {{{ */
-{
-  fc_target_t *t;
-
-  DEBUG ("fc_register_target (%s);", name);
-
-  t = (fc_target_t *) malloc (sizeof (*t));
-  if (t == NULL)
-    return (-ENOMEM);
-  memset (t, 0, sizeof (*t));
-
-  sstrncpy (t->name, name, sizeof (t->name));
-  memcpy (&t->proc, &proc, sizeof (t->proc));
-  t->next = NULL;
-
-  if (target_list_head == NULL)
-  {
-    target_list_head = t;
-  }
-  else
-  {
-    fc_target_t *ptr;
-
-    ptr = target_list_head;
-    while (ptr->next != NULL)
-      ptr = ptr->next;
-
-    ptr->next = t;
-  }
-
-  return (0);
-} /* }}} int fc_register_target */
-
-fc_chain_t *fc_chain_get_by_name (const char *chain_name) /* {{{ */
-{
-  fc_chain_t *chain;
-
-  if (chain_name == NULL)
-    return (NULL);
-
-  for (chain = chain_list_head; chain != NULL; chain = chain->next)
-    if (strcasecmp (chain_name, chain->name) == 0)
-      return (chain);
-
-  return (NULL);
-} /* }}} int fc_chain_get_by_name */
-
-int fc_process_chain (const data_set_t *ds, value_list_t *vl, /* {{{ */
-    fc_chain_t *chain)
-{
-  fc_rule_t *rule;
-  fc_target_t *target;
-  int status;
-
-  if (chain == NULL)
-    return (-1);
-
-  DEBUG ("fc_process_chain (chain = %s);", chain->name);
-
-  status = FC_TARGET_CONTINUE;
-  for (rule = chain->rules; rule != NULL; rule = rule->next)
-  {
-    fc_match_t *match;
-
-    if (rule->name[0] != 0)
-    {
-      DEBUG ("fc_process_chain (%s): Testing the `%s' rule.",
-          chain->name, rule->name);
-    }
-
-    /* N. B.: rule->matches may be NULL. */
-    for (match = rule->matches; match != NULL; match = match->next)
-    {
-      /* FIXME: Pass the meta-data to match targets here (when implemented). */
-      status = (*match->proc.match) (ds, vl, /* meta = */ NULL,
-          &match->user_data);
-      if (status < 0)
-      {
-        WARNING ("fc_process_chain (%s): A match failed.", chain->name);
-        break;
-      }
-      else if (status != FC_MATCH_MATCHES)
-        break;
-    }
-
-    /* for-loop has been aborted: Either error or no match. */
-    if (match != NULL)
-    {
-      status = FC_TARGET_CONTINUE;
-      continue;
-    }
-
-    if (rule->name[0] != 0)
-    {
-      DEBUG ("fc_process_chain (%s): Rule `%s' matches.",
-          chain->name, rule->name);
-    }
-
-    for (target = rule->targets; target != NULL; target = target->next)
-    {
-      /* If we get here, all matches have matched the value. Execute the
-       * target. */
-      /* FIXME: Pass the meta-data to match targets here (when implemented). */
-      status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL,
-          &target->user_data);
-      if (status < 0)
-      {
-        WARNING ("fc_process_chain (%s): A target failed.", chain->name);
-        continue;
-      }
-      else if (status == FC_TARGET_CONTINUE)
-        continue;
-      else if (status == FC_TARGET_STOP)
-        break;
-      else if (status == FC_TARGET_RETURN)
-        break;
-      else
-      {
-        WARNING ("fc_process_chain (%s): Unknown return value "
-            "from target `%s': %i",
-            chain->name, target->name, status);
-      }
-    }
-
-    if ((status == FC_TARGET_STOP)
-        || (status == FC_TARGET_RETURN))
-    {
-      if (rule->name[0] != 0)
-      {
-        DEBUG ("fc_process_chain (%s): Rule `%s' signaled "
-            "the %s condition.",
-            chain->name, rule->name,
-            (status == FC_TARGET_STOP) ? "stop" : "return");
-      }
-      break;
-    }
-    else
-    {
-      status = FC_TARGET_CONTINUE;
-    }
-  } /* for (rule) */
-
-  if (status == FC_TARGET_STOP)
-    return (FC_TARGET_STOP);
-  else if (status == FC_TARGET_RETURN)
-    return (FC_TARGET_CONTINUE);
-
-  DEBUG ("fc_process_chain (%s): Executing the default targets.",
-      chain->name);
-
-  status = FC_TARGET_CONTINUE;
-  for (target = chain->targets; target != NULL; target = target->next)
-  {
-    /* If we get here, all matches have matched the value. Execute the
-     * target. */
-    /* FIXME: Pass the meta-data to match targets here (when implemented). */
-    status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL,
-        &target->user_data);
-    if (status < 0)
-    {
-      WARNING ("fc_process_chain (%s): The default target failed.",
-          chain->name);
-    }
-    else if (status == FC_TARGET_CONTINUE)
-      continue;
-    else if (status == FC_TARGET_STOP)
-      break;
-    else if (status == FC_TARGET_RETURN)
-      break;
-    else
-    {
-      WARNING ("fc_process_chain (%s): Unknown return value "
-          "from target `%s': %i",
-          chain->name, target->name, status);
-    }
-  }
-
-  if ((status == FC_TARGET_STOP)
-      || (status == FC_TARGET_RETURN))
-  {
-    assert (target != NULL);
-    DEBUG ("fc_process_chain (%s): Default target `%s' signaled "
-        "the %s condition.",
-        chain->name, target->name,
-        (status == FC_TARGET_STOP) ? "stop" : "return");
-    if (status == FC_TARGET_STOP)
-      return (FC_TARGET_STOP);
-    else
-      return (FC_TARGET_CONTINUE);
-  }
-
-  DEBUG ("fc_process_chain (%s): Signaling `continue' at end of chain.",
-      chain->name);
-
-  return (FC_TARGET_CONTINUE);
-} /* }}} int fc_process_chain */
-
-/* Iterate over all rules in the chain and execute all targets for which all
- * matches match. */
-int fc_default_action (const data_set_t *ds, value_list_t *vl) /* {{{ */
-{
-  /* FIXME: Pass the meta-data to match targets here (when implemented). */
-  return (fc_bit_write_invoke (ds, vl,
-        /* meta = */ NULL, /* user_data = */ NULL));
-} /* }}} int fc_default_action */
-
-int fc_configure (const oconfig_item_t *ci) /* {{{ */
-{
-  fc_init_once ();
-
-  if (ci == NULL)
-    return (-EINVAL);
-
-  if (strcasecmp ("Chain", ci->key) == 0)
-    return (fc_config_add_chain (ci));
-
-  WARNING ("Filter subsystem: Unknown top level config option `%s'.",
-      ci->key);
-
-  return (-1);
-} /* }}} int fc_configure */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */