summaryrefslogtreecommitdiffstats
path: root/common/elapi/providers/file/file_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/elapi/providers/file/file_util.c')
-rw-r--r--common/elapi/providers/file/file_util.c504
1 files changed, 504 insertions, 0 deletions
diff --git a/common/elapi/providers/file/file_util.c b/common/elapi/providers/file/file_util.c
new file mode 100644
index 000000000..4508e35d1
--- /dev/null
+++ b/common/elapi/providers/file/file_util.c
@@ -0,0 +1,504 @@
+/*
+ ELAPI
+
+ Module contains internal utility functions for the file provider.
+
+ Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+ 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; either version 3 of the License, or
+ (at your option) any later version.
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include <errno.h> /* for errors */
+#include <stdlib.h> /* for free() */
+#include <string.h> /* for strlen() */
+
+/* To be able to serialize on needs to know the guts
+ * of the collection structure so have to include
+ * private header here.
+ */
+#include "collection_priv.h"
+#include "file_provider.h"
+#include "file_util.h"
+#include "ini_config.h"
+#include "trace.h"
+#include "config.h"
+
+#ifdef ELAPI_VERBOSE
+/* FIXME: remove when api is stable */
+#include "collection_tools.h"
+#endif
+
+char empty[] = "";
+
+/* Callback to prepare set for splitting */
+static int file_set_clean_cb(const char *property,
+ int property_len,
+ int type,
+ void *data,
+ int length,
+ void *custom_data,
+ int *stop)
+{
+ int error = EOK;
+ TRACE_FLOW_STRING("file_set_clean_cb", "Entry");
+
+ /* Skip header */
+ if (type == COL_TYPE_COLLECTION) return EOK;
+
+ /* Clean data */
+ *((struct collection_item **)(data)) = NULL;
+
+ TRACE_FLOW_STRING("file_set_clean_cb", "Exit");
+ return error;
+}
+
+/* Function to split event into two parts by given set */
+static int file_split_by_set(struct collection_item **leftovers,
+ struct file_prvdr_cfg *cfg,
+ struct collection_item *event)
+{
+ int error = EOK;
+ struct collection_item *item_event;
+ struct collection_item *item_set;
+ struct collection_iterator *it_event;
+ struct collection_iterator *it_set;
+ struct collection_item *lo = NULL;
+ int found = 0;
+ TRACE_FLOW_STRING("file_split_by_set", "Entry");
+
+ /* First prepare set for use */
+ error = col_traverse_collection(cfg->set,
+ COL_TRAVERSE_ONELEVEL,
+ file_set_clean_cb,
+ NULL);
+ if (error) {
+ TRACE_ERROR_NUMBER("Traverse set failed.", error);
+ return error;
+ }
+
+ /* If we are going to use leftovers create a collection */
+ if (cfg->use_leftovers) {
+ error = col_create_collection(&lo,
+ FILE_LO_NAME,
+ FILE_LO_CLASS);
+ if (error) {
+ TRACE_ERROR_NUMBER("Faild to create collection.", error);
+ return error;
+ }
+ }
+
+ /* Now all items from the set are NULLs */
+ /* Split the event in two parts */
+ /* We need to iterate through the event rather than use a callback. */
+ /* Bind iterator */
+ error = col_bind_iterator(&it_event, event, COL_TRAVERSE_FLAT);
+ if (error) {
+ TRACE_ERROR_NUMBER("Error bind iterator for event failed:", error);
+ /* Here and below it is safe to destroy it event if is NULL. */
+ col_destroy_collection(lo);
+ return error;
+ }
+
+ while(1) {
+ /* Loop through the event */
+ error = col_iterate_collection(it_event, &item_event);
+ if (error) {
+ TRACE_ERROR_NUMBER("Error iterating event:", error);
+ col_unbind_iterator(it_event);
+ col_destroy_collection(lo);
+ return error;
+ }
+
+ /* Are we done ? */
+ if (item_event == NULL) break;
+
+ /* Skip headers */
+ if (item_event->type == COL_TYPE_COLLECTION) continue;
+
+ /* For each item in the event find an item in the set */
+ error = col_bind_iterator(&it_set, cfg->set, COL_TRAVERSE_ONELEVEL);
+ if (error) {
+ TRACE_ERROR_NUMBER("Error bind iterator for set failed:", error);
+ col_unbind_iterator(it_event);
+ col_destroy_collection(lo);
+ return error;
+ }
+
+ found = 0;
+ while(1) {
+ /* Loop through the event */
+ error = col_iterate_collection(it_set, &item_set);
+ if (error) {
+ TRACE_ERROR_NUMBER("Error iterating set:", error);
+ col_unbind_iterator(it_event);
+ col_unbind_iterator(it_set);
+ col_destroy_collection(lo);
+ return error;
+ }
+
+ /* Are we done ? */
+ if (item_set == NULL) break;
+
+ /* Skip headers */
+ if (item_set->type == COL_TYPE_COLLECTION) continue;
+
+ /* Hashes should match and the data in the set should be NULL,
+ * and legths should be same.
+ */
+ if ((item_event->phash == item_set->phash) &&
+ (*((struct collection_item **)(item_set->data)) == NULL) &&
+ (item_event->property_len == item_set->property_len)) {
+ /* This is a candidate for match - compare strings */
+ TRACE_INFO_STRING("Found a good candidate for match.","");
+ TRACE_INFO_STRING("Set item:", item_set->property);
+ TRACE_INFO_STRING("Event:", item_event->property);
+
+ if (strncasecmp(item_set->property,
+ item_event->property,
+ item_event->property_len) == 0) {
+ TRACE_INFO_STRING("Match found!","");
+ TRACE_INFO_STRING("Set item:", item_set->property);
+ TRACE_INFO_STRING("Event:", item_event->property);
+
+ *((struct collection_item **)(item_set->data)) = item_event;
+ found = 1;
+ break;
+ }
+ }
+ }
+ /* Done with the set */
+ col_unbind_iterator(it_set);
+
+ /* Is it a leftover ? */
+ if ((!found) && (cfg->use_leftovers)) {
+ /* We need to put it in the leftovers pile */
+ /* To save time and space we do not care about property name.
+ * The property name is going to be in the referenced item.
+ */
+ error = col_add_binary_property(lo,
+ NULL,
+ "",
+ (void *)(&item_event),
+ sizeof(struct collection_item *));
+ if (error) {
+ TRACE_ERROR_NUMBER("Error addding item to leftovers:", error);
+ col_unbind_iterator(it_event);
+ col_destroy_collection(lo);
+ return error;
+ }
+ }
+ }
+
+ /* Done with the event */
+ col_unbind_iterator(it_event);
+
+ /* Save leftovers if any */
+ *leftovers = lo;
+
+ TRACE_FLOW_STRING("file_spserialized_lo->bufferlit_by_set", "Exit");
+ return error;
+}
+
+/* Function to serialize one item */
+static int file_serialize_item(struct elapi_data_out *out_data,
+ int type,
+ int length,
+ void *data,
+ uint32_t mode,
+ void *mode_cfg)
+{
+ int error = EOK;
+ TRACE_FLOW_STRING("file_serialize_item", "Entry");
+
+ switch(mode) {
+ case FILE_MODE_CSV:
+ error = file_serialize_csv(out_data,
+ type,
+ length,
+ data,
+ mode_cfg);
+ break;
+/* FIXME : add other iterative formats later */
+/*
+ case FILE_MODE_HTML:
+ error = file_serialize_html(out_data,
+ type,
+ length,
+ data,
+ mode_cfg);
+ break;
+ case FILE_MODE_XML:
+ error = file_serialize_xml(out_data,
+ type,
+ length,
+ data,
+ mode_cfg);
+ break;
+ case FILE_MODE_JSON:
+ error = file_serialize_json(out_data,
+ type,
+ length,
+ data,
+ mode_cfg);
+ break;
+ case FILE_MODE_KVP:
+ error = file_serialize_kvp(out_data,
+ type,
+ length,
+ data,
+ mode_cfg);
+ break;
+*/
+ default:
+ TRACE_ERROR_STRING("Unsupported mode", "Fatal error!");
+ error = EINVAL;
+
+ }
+
+ TRACE_FLOW_STRING("file_serialize_item", "Exit");
+ return error;
+
+}
+
+
+
+/* Function to serialize the list */
+static int file_serialize_list(struct elapi_data_out **out_data,
+ int append,
+ int reference,
+ struct collection_item *input,
+ uint32_t mode,
+ void *mode_cfg)
+{
+ int error = EOK;
+ struct elapi_data_out *allocated = NULL;
+ struct elapi_data_out *to_use = NULL;
+ struct collection_iterator *iterator;
+ struct collection_item *item;
+
+ TRACE_FLOW_STRING("file_serialize_list", "Entry");
+
+ /* Allocate storage if we are not appending */
+ if (!append) {
+ error = elapi_alloc_serialized_data(&allocated);
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to allocated serialized data", error);
+ return error;
+ }
+ TRACE_INFO_STRING("Allocated new out data", "");
+ to_use = allocated;
+ }
+ else {
+ TRACE_INFO_STRING("Appening, use passed in output data", "");
+ to_use = *out_data;
+ }
+
+ /* FIXME: This logic works for iterative formats only. */
+ /* When we implement the free form format this
+ * logic should be augmented. */
+
+#ifdef ELAPI_VERBOSE
+ /* FIXME: remove when stable */
+ col_debug_collection(input, COL_TRAVERSE_FLAT);
+#endif
+
+
+ /* Start iterating */
+ error = col_bind_iterator(&iterator, input, COL_TRAVERSE_FLAT);
+ if (error) {
+ TRACE_ERROR_NUMBER("Error bind iterator failed:", error);
+ return error;
+ }
+
+ while(1) {
+ /* Loop through the collection */
+ error = col_iterate_collection(iterator, &item);
+ if (error) {
+ TRACE_ERROR_NUMBER("Error iterating event:", error);
+ col_unbind_iterator(iterator);
+ /* Free allocated data if we allocated it */
+ elapi_free_serialized_data(allocated);
+ return error;
+ }
+
+ /* Are we done ? */
+ if (item == NULL) break;
+
+ /* Skip headers */
+ if (item->type == COL_TYPE_COLLECTION) continue;
+
+ /* Got item */
+ if (reference) {
+ /* Derefernce the item before using */
+ item = *((struct collection_item **)(item->data));
+ }
+
+ if (item) {
+ TRACE_ERROR_NUMBER("Item property", item->property);
+
+ /* Serialize this item */
+ error = file_serialize_item(to_use,
+ item->type,
+ item->length,
+ item->data,
+ mode,
+ mode_cfg);
+ }
+ else {
+ /* Serialize this item */
+ error = file_serialize_item(to_use,
+ COL_TYPE_BINARY,
+ 0,
+ NULL,
+ mode,
+ mode_cfg);
+ }
+
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to serialize item", error);
+ col_unbind_iterator(iterator);
+ /* Free allocated data if we allocated it */
+ elapi_free_serialized_data(allocated);
+ return error;
+ }
+ }
+ col_unbind_iterator(iterator);
+
+ *out_data = to_use;
+
+ TRACE_FLOW_STRING("file_serialize_list", "Exit");
+ return error;
+}
+
+/* Function to log event into sink */
+int file_prep_data(struct elapi_data_out **out_data,
+ struct file_prvdr_ctx *ctx,
+ struct collection_item *event)
+{
+ int error = EOK;
+ struct elapi_data_out *serialized = NULL;
+ struct elapi_data_out *serialized_lo = NULL;
+ struct collection_item *leftovers = NULL;
+
+ TRACE_FLOW_STRING("file_prep_data", "Entry");
+
+ /* Do we need to split the data into two parts by set ? */
+ if (ctx->config.set) {
+ /* Split collection based on the configured set of fields */
+ error = file_split_by_set(&leftovers,
+ &(ctx->config),
+ event);
+ if (error) {
+ TRACE_ERROR_NUMBER("Split collection returned error", error);
+ return error;
+ }
+
+ /* Serialize main items */
+ error = file_serialize_list(&serialized,
+ FILE_SER_NEW,
+ FILE_ITEM_REF,
+ ctx->config.set,
+ ctx->config.outmode,
+ ctx->config.main_fmt_cfg);
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to serialize main set", error);
+ col_destroy_collection(leftovers);
+ return error;
+ }
+
+ if (ctx->config.use_leftovers) {
+ /* Do we have to jam leftovers? */
+ if (ctx->config.jam_leftovers) {
+ /* Serialise leftovers into one field */
+ error = file_serialize_list(&serialized_lo,
+ FILE_SER_NEW,
+ FILE_ITEM_REF,
+ leftovers,
+ ctx->config.mode_leftovers,
+ ctx->config.lo_fmt_cfg);
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to serialize main set", error);
+ col_destroy_collection(leftovers);
+ elapi_free_serialized_data(serialized);
+ return error;
+ }
+
+ /* Check if we go anything */
+ if (serialized_lo->length) {
+ /* Append leftovers item */
+ error = file_serialize_item(serialized,
+ COL_TYPE_STRING,
+ serialized_lo->length + 1,
+ serialized_lo->buffer,
+ ctx->config.outmode,
+ ctx->config.main_fmt_cfg);
+ }
+ else {
+ /* Put empty item */
+ error = file_serialize_item(serialized,
+ COL_TYPE_BINARY,
+ 0,
+ NULL,
+ ctx->config.outmode,
+ ctx->config.main_fmt_cfg);
+ }
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to serialize main set", error);
+ col_destroy_collection(leftovers);
+ elapi_free_serialized_data(serialized);
+ elapi_free_serialized_data(serialized_lo);
+ return error;
+ }
+
+ /* Done with the jammed leftovers */
+ elapi_free_serialized_data(serialized_lo);
+ }
+ else {
+ /* Leftovers are added as normal fields */
+ error = file_serialize_list(&serialized,
+ FILE_SER_APPEND,
+ FILE_ITEM_REF,
+ leftovers,
+ ctx->config.outmode,
+ ctx->config.main_fmt_cfg);
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to serialize main set", error);
+ col_destroy_collection(leftovers);
+ elapi_free_serialized_data(serialized);
+ return error;
+ }
+ }
+ /* Do not need leftovers */
+ col_destroy_collection(leftovers);
+ }
+ }
+ else {
+ /* No set is defined - the whole event is processed */
+ error = file_serialize_list(&serialized,
+ FILE_SER_NEW,
+ FILE_ITEM_DIRECT,
+ event,
+ ctx->config.outmode,
+ ctx->config.main_fmt_cfg);
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to serialize event", error);
+ return error;
+ }
+ }
+
+ *out_data = serialized;
+
+ TRACE_FLOW_STRING("file_prep_data", "Exit");
+ return error;
+
+}