diff options
Diffstat (limited to 'common/elapi/providers/file/file_provider.c')
-rw-r--r-- | common/elapi/providers/file/file_provider.c | 576 |
1 files changed, 551 insertions, 25 deletions
diff --git a/common/elapi/providers/file/file_provider.c b/common/elapi/providers/file/file_provider.c index 589ed5eb..09d6261e 100644 --- a/common/elapi/providers/file/file_provider.c +++ b/common/elapi/providers/file/file_provider.c @@ -20,34 +20,530 @@ #define _GNU_SOURCE #include <errno.h> /* for errors */ #include <stdlib.h> /* for free() */ +#include <string.h> /* for strlen() */ +#include <unistd.h> /* for close() */ #include "file_provider.h" +#include "file_util.h" +#include "file_fmt_csv.h" #include "ini_config.h" #include "trace.h" #include "config.h" -/* FIXME: temporary for debugging */ + +/* NOTE: Each format module has its own header */ +#include "file_fmt_csv.h" +/* Add headers for new formats here... */ + +/*******************************************************************/ +/* SECTION FOR INTERNAL CONDITIONALLY COMPILED DEBUGGING FUNCTIONS */ +/*******************************************************************/ +#ifdef ELAPI_VERBOSE #include "collection_tools.h" +/* Function to debug format configurations */ +void file_print_fmt_cfg(uint32_t mode, void *fmt_cfg) +{ + switch(mode) { + case FILE_MODE_CSV: + file_print_fmt_csv(fmt_cfg); + break; + /* FIXME : add other formats later */ +/* + case FILE_MODE_FORMAT: + error = file_print_fmt_format(fmt_cfg); + break; + case FILE_MODE_HTML: + error = file_print_fmt_html(fmt_cfg); + break; + case FILE_MODE_XML: + error = file_print_fmt_xml(fmt_cfg); + break; + case FILE_MODE_JSON: + error = file_print_fmt_json(fmt_cfg); + break; + case FILE_MODE_KVP: + error = file_print_fmt_kvp(fmt_cfg); + break; +*/ + default: + printf("Unsupported mode!\n"); + } +} + + +/* Function for debugging configuration */ +void file_print_cfg(struct file_prvdr_cfg *cfg) +{ + printf("File provider configuration\n"); + + printf(" File name: [%s]\n", ((cfg->filename != NULL) ? cfg->filename : "NULL")); + printf(" Own file : [%s]\n", ((cfg->ownfile > 0) ? "yes" : "no")); + printf(" Keep open: [%s]\n", ((cfg->keepopen > 0) ? "yes" : "no")); + + if (cfg->fsyncmode == 0) { + printf(" Sync mode: [no flush]\n"); + } + else if (cfg->fsyncmode > 0) { + printf(" Sync mode: every [%d] event\n", cfg->fsyncmode); + } + else { + printf(" Sync mode: every [%d] second\n", 0 - cfg->fsyncmode); + } + + if (cfg->set) { + printf(" There is a set of predefined fields\n"); + col_print_collection(cfg->set); + printf(" Use leftovers: [%s]\n", ((cfg->use_leftovers > 0) ? "yes" : "no")); + printf(" Jam leftovers: [%s]\n", ((cfg->jam_leftovers > 0) ? "yes" : "no")); + if (cfg->use_leftovers > 0) { + printf("Leftovers configuration:\n"); + file_print_fmt_cfg(cfg->mode_leftovers, cfg->lo_fmt_cfg); + printf("Leftovers configuration END\n"); + } + } + else printf("All fields go into the output.\n"); + + + printf("Main configuration:\n"); + file_print_fmt_cfg(cfg->outmode, cfg->main_fmt_cfg); + printf("Main configuration END:\n"); + + printf("File provider configuration END\n"); + +} + +/* Function to debug context */ +void file_print_ctx(struct file_prvdr_ctx *ctx) +{ + if (ctx == NULL) { + printf("No file provider context!\n"); + return; + } + + printf("File Provider Context\n"); + + /* Print configuration */ + file_print_cfg(&(ctx->config)); + + /* Print other parts of the context */ + printf("File is currently: [%s]\n", ((ctx->outfile >= 0) ? "open" : "closed")); + printf("File Provider Context END\n\n"); + +} +#endif + +/*******************************************************************/ +/* MAIN MODULE FUNCTIONS */ +/*******************************************************************/ + +/* Function that reads the specific configuration + * information about the format of the output + */ +static int file_read_fmt_cfg(void **storage, + uint32_t mode, + const char *name, + struct collection_item *ini_config, + const char *appname) +{ + int error = EOK; + + TRACE_FLOW_STRING("file_read_fmt_cfg", "Entry"); + + switch(mode) { + case FILE_MODE_CSV: + error = file_get_csv_cfg(storage, name, ini_config, appname); + break; + /* FIXME : add other formats later */ +/* + case FILE_MODE_FORMAT: + error = file_get_format_cfg(storage, name, ini_config, appname); + break; + case FILE_MODE_HTML: + error = file_get_html_cfg(storage, name, ini_config, appname); + break; + case FILE_MODE_XML: + error = file_get_xml_cfg(storage, name, ini_config, appname); + break; + case FILE_MODE_JSON: + error = file_get_json_cfg(storage, name, ini_config, appname); + break; + case FILE_MODE_KVP: + error = file_get_kvp_cfg(storage, name, ini_config, appname); + break; +*/ + default: + TRACE_ERROR_STRING("Unsupported mode", "Fatal error!"); + error = EINVAL; + + } + TRACE_FLOW_NUMBER("file_read_fmt_cfg. Exit. Returning:", error); + return error; +} + +/* Function to build the set object from the configuration data */ +static int file_build_set(struct file_prvdr_cfg *file_cfg, + struct collection_item *cfg_item) +{ + int error = EOK; + char **fields; + char *field; + int size; + int count; + struct collection_item *dummy = NULL; + struct collection_item *set = NULL; + + TRACE_FLOW_STRING("file_build_set", "Entry"); + + /* Get fields array from config field */ + fields = get_string_config_array(cfg_item, NULL, &size, &error); + if (error) { + TRACE_ERROR_NUMBER("Attempt to get set items returned error", error); + return error; + } + + if (size > 0) { + + TRACE_INFO_STRING("We have the set of required fields", ""); + + /* Create collection */ + error = col_create_collection(&set, FILE_FIELDSET_COL, FILE_FIELDSET_CLASS); + if (error) { + TRACE_ERROR_NUMBER("Attempt to create collection failed", error); + return error; + } + + for (count = 0; count < size; count++) { + field = fields[count]; + TRACE_INFO_STRING("FIELD:", field); + + if (field[0] == FILE_SET_END) { + TRACE_INFO_STRING("Leftovers field found.", ""); + if (count != (size - 1)) { + /* We found an end list field in the middle - error */ + TRACE_ERROR_NUMBER("More fields after end list field.", EINVAL); + col_destroy_collection(set); + free_string_config_array(fields); + return EINVAL; + } + + file_cfg->use_leftovers = 1; + + /* What format to use leftovers ? */ + /* NOTE: Is we ever support more than 10 formats + * this logic needs to change + */ + if ((field[1] >= '0') && + (field[1] <= ('0' + FILE_MAXMODE)) && + (field[2] == '\0')) { + /* We have a format specifier */ + file_cfg->mode_leftovers = (uint32_t)(field[1] - '0'); + file_cfg->jam_leftovers = 1; + TRACE_INFO_NUMBER("Use mode for leftovers:", file_cfg->mode_leftovers); + } + else { + /* Wrong format */ + TRACE_ERROR_NUMBER("Leftover field has invalid format.", EINVAL); + col_destroy_collection(set); + free_string_config_array(fields); + return EINVAL; + } + + } + else { + error = col_add_binary_property(set, + NULL, + field, + &dummy, + sizeof(struct collection_item *)); + if (error) { + TRACE_ERROR_NUMBER("Error adding item to the set.", error); + col_destroy_collection(set); + free_string_config_array(fields); + return error; + } + } + } + + file_cfg->set = set; + } + + /* Free the list */ + free_string_config_array(fields); + + TRACE_FLOW_STRING("file_build_set", "Exit"); + return error; +} + /* Function to read configuration */ -int file_read_cfg(struct file_prvdr_cfg *file_cfg, - char *name, - struct collection_item *ini_config) +static int file_read_cfg(struct file_prvdr_cfg *file_cfg, + const char *name, + struct collection_item *ini_config, + const char *appname) { int error = EOK; + struct collection_item *cfg_item = NULL; + const char *filename; + int use_default_name = 0; + TRACE_FLOW_STRING("file_read_cfg", "Entry point"); - /* FIXME: read configuration items */ + /*********** Filename *************/ + + /* Get file name */ + error = get_config_item(name, + FILE_OUTNAME, + ini_config, + &cfg_item); + if (error) { + TRACE_ERROR_NUMBER("Attempt to read \"filename\" attribute returned error", error); + return error; + } + /* Do we have file name? */ + if (cfg_item == NULL) use_default_name = 1; + else { + /* Get file name from configuration */ + error = EOK; + filename = get_const_string_config_value(cfg_item, &error); + if (error) { + TRACE_ERROR_STRING("Failed to get value from configuration.", "Fatal Error!"); + return error; + } + /* Check if file name is empty */ + if (filename[0] == '\0') use_default_name = 1; + else { + /* Now get a copy */ + file_cfg->filename = get_string_config_value(cfg_item, &error); + if (error) { + TRACE_ERROR_STRING("Failed to copy value from configuration.", "Fatal Error!"); + return error; + } + } + } + + if (use_default_name) { + /* There is no file name - use default */ + file_cfg->filename = malloc(strlen(appname) + sizeof(FILE_SUFFIX)); + if (file_cfg->filename == NULL) { + TRACE_ERROR_STRING("Failed to allocate memory for file name.", "Fatal Error!"); + return ENOMEM; + } + /* Appname is validated in the elapi_log.c */ + /* This should be safe to do */ + strcpy(file_cfg->filename, appname); + strcat(file_cfg->filename, FILE_SUFFIX); + + file_cfg->ownfile = 1; + } + else if (strcmp(filename, FILE_STDERR) != 0) file_cfg->ownfile = 1; + else file_cfg->ownfile = 0; + + /*********** Keep open *************/ + /* Next is "keepopen" field */ + + cfg_item = NULL; + error = get_config_item(name, + FILE_KEEPOPEN, + ini_config, + &cfg_item); + if (error) { + TRACE_ERROR_NUMBER("Attempt to read \"keepopen\" attribute returned error", error); + return error; + } + + /* Do we have "keepopen"? */ + if (cfg_item == NULL) { + /* There is no attribute - assume default */ + TRACE_INFO_STRING("No \"keepopen\" attribute.", "Assume open on each entry"); + file_cfg->keepopen = 0; + } + else { + file_cfg->keepopen = (uint32_t) get_bool_config_value(cfg_item, '\0', &error); + if (error) { + TRACE_ERROR_STRING("Invalid \"keepopen\" value", "Fatal Error!"); + return EINVAL; + } + } + + /*********** Outmode *************/ + /* Next is "outmode" field */ + + cfg_item = NULL; + error = get_config_item(name, + FILE_OUTMODE, + ini_config, + &cfg_item); + if (error) { + TRACE_ERROR_NUMBER("Attempt to read \"outmode\" attribute returned error", error); + return error; + } + + /* Do we have "outmode"? */ + if (cfg_item == NULL) { + /* There is no attribute - assume default */ + TRACE_INFO_STRING("No \"outmode\" attribute.", "Assume CSV kind"); + file_cfg->outmode = 0; + } + else { + file_cfg->outmode = (uint32_t) get_unsigned_config_value(cfg_item, 1, 0, &error); + if (error) { + TRACE_ERROR_STRING("Invalid \"outmode\" value", "Fatal Error!"); + return EINVAL; + } + /* Check for right range */ + if (file_cfg->outmode > FILE_MAXMODE) { + TRACE_ERROR_STRING("Invalid \"outmode\" value - out of range", "Fatal Error!"); + return ERANGE; + } + } + + /*********** Sync mode *************/ + /* Next is sync mode field */ + + cfg_item = NULL; + error = get_config_item(name, + FILE_FLUSH, + ini_config, + &cfg_item); + if (error) { + TRACE_ERROR_NUMBER("Attempt to read \"fsyncmode\" attribute returned error", error); + return error; + } + + /* Do we have "fsyncmode"? */ + if (cfg_item == NULL) { + /* There is no attribute - assume default */ + TRACE_INFO_STRING("No \"fsyncmode\" attribute.", "Assume CSV kind"); + file_cfg->fsyncmode = 0; + } + else { + file_cfg->fsyncmode = (int32_t) get_int_config_value(cfg_item, 1, 0, &error); + if (error) { + TRACE_ERROR_STRING("Invalid \"fsyncmode\" value", "Fatal Error!"); + return EINVAL; + } + } + + /*********** Set *************/ + /* Next is the "set" field */ + cfg_item = NULL; + error = get_config_item(name, + FILE_FIELDSET, + ini_config, + &cfg_item); + if (error) { + TRACE_ERROR_NUMBER("Attempt to read \"set\" attribute returned error", error); + return error; + } + + file_cfg->use_leftovers = 0; + file_cfg->jam_leftovers = 0; + file_cfg->mode_leftovers = file_cfg->outmode; + + /* Do we have "required"? */ + if (cfg_item == NULL) { + /* There is no attribute - assume default */ + TRACE_INFO_STRING("No \"set\" attribute.", "Assume all fields as specified"); + file_cfg->set = NULL; + } + else { + error = file_build_set(file_cfg, cfg_item); + if (error) { + TRACE_ERROR_STRING("Invalid \"set\" value", "Fatal Error!"); + return EINVAL; + } + } + + /*********** Format specific configurations *************/ + /* Read the main format configuration details */ + error = file_read_fmt_cfg((void **)(&(file_cfg->main_fmt_cfg)), + file_cfg->outmode, + name, + ini_config, + appname); + if (error) { + TRACE_ERROR_NUMBER("Failed to read main format configuration", error); + return error; + } + + if (file_cfg->use_leftovers) { + /* If we use same mode for leftovers and main do not read things again */ + if (file_cfg->mode_leftovers == file_cfg->outmode) { + TRACE_INFO_STRING("Output modes are the same", ""); + file_cfg->lo_fmt_cfg = file_cfg->main_fmt_cfg; + } + else { + TRACE_INFO_STRING("Output modes are the different", ""); + TRACE_INFO_NUMBER("Main mode", file_cfg->outmode); + TRACE_INFO_NUMBER("Left over's mode", file_cfg->mode_leftovers); + + /* Read the leftover's format configuration details */ + error = file_read_fmt_cfg((void **)(&(file_cfg->lo_fmt_cfg)), + file_cfg->mode_leftovers, + name, + ini_config, + appname); + if (error) { + TRACE_ERROR_NUMBER("Failed to read main format configuration", error); + return error; + } + } + } TRACE_FLOW_STRING("file_read_cfg", "Exit"); return error; } +/* Function to destroy the context */ +static void file_destroy_ctx(struct file_prvdr_ctx **file_ctx) +{ + TRACE_FLOW_STRING("file_destroy_ctx", "Entry"); + + if ((file_ctx) && (*file_ctx)) { + /* Close file if it is open */ + if (((*file_ctx)->outfile >= 0) && ((*file_ctx)->config.ownfile)) { + TRACE_INFO_STRING("File was open", ""); + close((*file_ctx)->outfile); + } + + /* Free file name if it is not NULL */ + if ((*file_ctx)->config.filename) { + TRACE_INFO_STRING("Freeing file name", (*file_ctx)->config.filename); + free((*file_ctx)->config.filename); + } + + /* Free set if any */ + if ((*file_ctx)->config.set) { + TRACE_INFO_NUMBER("Freeing set", (*file_ctx)->config.set); + col_destroy_collection((*file_ctx)->config.set); + } + + /* Free main format configuration if it is not NULL */ + if (((*file_ctx)->config.main_fmt_cfg) && + ((*file_ctx)->config.main_fmt_cfg != (*file_ctx)->config.lo_fmt_cfg)) { + TRACE_INFO_NUMBER("Freeing main format config.", (*file_ctx)->config.main_fmt_cfg); + free((*file_ctx)->config.main_fmt_cfg); + } + + /* Free left over format configuration if it is not NULL */ + if ((*file_ctx)->config.lo_fmt_cfg) { + TRACE_INFO_NUMBER("Freeing leftover format config.", (*file_ctx)->config.lo_fmt_cfg); + free((*file_ctx)->config.lo_fmt_cfg); + } + + TRACE_FLOW_STRING("Freeing file context", "Entry"); + free(*file_ctx); + *file_ctx = NULL; + } + + TRACE_FLOW_STRING("file_destroy_ctx", "Exit"); +} /* Function to create context */ -int file_create_ctx(struct file_prvdr_ctx **file_ctx, - char *name, - struct collection_item *ini_config) +static int file_create_ctx(struct file_prvdr_ctx **file_ctx, + const char *name, + struct collection_item *ini_config, + const char *appname) { int error = EOK; struct file_prvdr_ctx *ctx = NULL; @@ -62,12 +558,15 @@ int file_create_ctx(struct file_prvdr_ctx **file_ctx, /* Init allocatable items */ ctx->config.filename = NULL; + ctx->config.main_fmt_cfg = NULL; + ctx->config.lo_fmt_cfg = NULL; + ctx->outfile = -1; /* Read configuration data */ - error = file_read_cfg(&(ctx->config), name, ini_config); + error = file_read_cfg(&(ctx->config), name, ini_config, appname); if (error) { TRACE_ERROR_NUMBER("Error reading sink configuration", error); - free(ctx); + file_destroy_ctx(&ctx); return error; } @@ -80,8 +579,9 @@ int file_create_ctx(struct file_prvdr_ctx **file_ctx, /* File init function */ int file_init(void **priv_ctx, - char *name, - struct collection_item *ini_config) + const char *name, + struct collection_item *ini_config, + const char *appname) { int error = EOK; TRACE_FLOW_STRING("file_init", "Entry point"); @@ -89,15 +589,21 @@ int file_init(void **priv_ctx, /* Start with creating context */ error = file_create_ctx((struct file_prvdr_ctx **)priv_ctx, name, - ini_config); + ini_config, + appname); if (error) { TRACE_ERROR_NUMBER("Failed to create context", error); return error; } - /* Open file */ + /* Open file */ /* FIXME: ... */ +#ifdef ELAPI_VERBOSE + printf("Initializaing file provider for sink: [%s]\n", name); + file_print_ctx(*((struct file_prvdr_ctx **)priv_ctx)); +#endif + TRACE_FLOW_STRING("file_init", "Exit"); return error; } @@ -111,18 +617,11 @@ void file_close(void **priv_ctx) ctx = (struct file_prvdr_ctx **)priv_ctx; - /* Close file */ - /* FIXME: ... */ - - /* If we allocated file name free it */ - if ((*ctx)->config.filename != NULL) { - TRACE_INFO_STRING("Freeing file name", (*ctx)->config.filename); - free((*ctx)->config.filename); - } +#ifdef ELAPI_VERBOSE + file_print_ctx(*ctx); +#endif - /* Free and indicate that the context is freed */ - free(*ctx); - *ctx = NULL; + file_destroy_ctx(ctx); TRACE_FLOW_STRING("file_close", "Exit"); } @@ -131,11 +630,38 @@ void file_close(void **priv_ctx) int file_submit(void *priv_ctx, struct collection_item *event) { int error = EOK; + struct file_prvdr_ctx *ctx = (struct file_prvdr_ctx *)priv_ctx; + struct elapi_data_out *out_data; + TRACE_FLOW_STRING("file_submit", "Entry point"); +#ifdef ELAPI_VERBOSE + file_print_ctx(ctx); /* FIXME: Placeholder for now */ col_print_collection(event); +#endif + + /* FIXME: Open file here if it is closed */ + + error = file_prep_data(&out_data, ctx, event); + if (error) { + TRACE_ERROR_NUMBER("Failed to prepare data", error); + return error; + } + + /* FIXME: just print it for now!!! */ + + printf("EVENT: [%*s]\n", out_data->length, out_data->buffer); + + + /* FIXME: write data base on the synch or not synch mode of the sink */ + /* For now we will just assume synch */ + /* This function will probably be a part of the common callbacks */ + /* elapi_write_to_fd(out_data, ctx_>outfile); */ + + /* This one is temporary here too */ + elapi_free_serialized_data(out_data); TRACE_FLOW_STRING("file_sumbit", "Exit"); return error; |