/* ELAPI Implemenation of the file sink. Copyright (C) Dmitri Pal 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 . */ #include #include #include #include #include "elapi_sink.h" #include "elapi_collection.h" #include "elapi_debug.h" #include "elapi_util.h" #include "elapi_ini.h" /* FIXME - this should be taken from the config.h generated by autotools */ #define FILE_RETRY 60 /* #define FILE_AUDIT_CONFIG "/etc/elapi/file_defaults.conf" #define FILE_AUDIT_DIR "/etc/elapi/file_defaults.d" */ #define FILE_AUDIT_CONFIG "/home/dpal/IPA/Code/elapi/etc/file_defaults.conf" #define FILE_AUDIT_DIR "/home/dpal/IPA/Code/elapi/etc/file_defaults.d" /* FIXME there is currently no code * to make sure we do not call syslog functions from multiple dispatchers. * We probably should create a mutex at the load of the library and * set a flag when the init function is called the first time * and not call the openlog any more times. * But I guess syslog can deal with this internally. */ /* Default conmfiguration for syslog */ struct file_conf { int keep_open; char *file_name; FILE *file; }; /* Internal function to intialize configuration */ static int init_config(struct data_descriptor *dblock) { struct file_conf *conf_data; struct collection_item *config_from_file = (struct collection_item *)(NULL); int found = 0; int *keep_open_cfg = (int *)(NULL); char *file_name_cfg = NULL; int error; DEBUG_STRING("init_config","Entry"); /* Allocate configuration data */ conf_data = (struct file_conf *)(malloc(sizeof(struct file_conf))); if(conf_data == (struct file_conf *)(NULL)) return errno; /* Read configuration from the configuration file if any */ (void)config_to_collection(dblock->appname, FILE_AUDIT_CONFIG, FILE_AUDIT_DIR, &config_from_file); conf_data->keep_open = 1; conf_data->file_name = NULL; DEBUG_NUMBER("Keep open:",conf_data->keep_open); DEBUG_STRING("File name:",conf_data->file_name); /* Update defaults with settings from the file */ error = get_value_from_config((void *)(&keep_open_cfg),ELAPI_TYPE_INTEGER, INI_DEFAULT_SECTION,"keep_open",config_from_file); if(error != EOK) { /* There is fundamentally something wrong */ DEBUG_NUMBER("Attempt to get option returned error",error); free((void *)(conf_data)); return error; } /* Get the value */ if(keep_open_cfg != (int *)(NULL)) { conf_data->keep_open = *keep_open_cfg; free((void *)(keep_open_cfg)); } error = get_value_from_config((void *)(&file_name_cfg),ELAPI_TYPE_STRING, INI_DEFAULT_SECTION,"file_name",config_from_file); if(error != EOK) { /* There is fundamentally something wrong */ DEBUG_NUMBER("Attempt to get option returned error",error); free((void *)(conf_data)); return error; } /* Get the value */ if(file_name_cfg != (char *)(NULL)) { conf_data->file_name = file_name_cfg; } DEBUG_NUMBER("Keep open (after conf file):",conf_data->keep_open); DEBUG_STRING("File name (after conf file):",conf_data->file_name); dblock->config = (void *)(conf_data); if((conf_data->file_name != NULL) && (conf_data->keep_open != 0)) { conf_data->file = fopen(conf_data->file_name,"w"); } else conf_data->file = stderr; DEBUG_STRING("init_config","Entry"); return EOK; } /***** Standard functions each facility has to provide *****/ /* Initialize facility - open files, establish connnectons, etc... */ static int file_sink_init(struct data_descriptor *dblock) { struct serial_data *event_storage; int error; DEBUG_STRING("file_sink_init","Entry"); /* Prepare the block where the format function will store its data */ errno = 0; dblock->internal_data = NULL; event_storage = (struct serial_data *)(malloc(sizeof(struct serial_data))); if(event_storage == (struct serial_data *)(NULL)) return errno; event_storage->buffer = NULL; event_storage->size = 0; event_storage->length = 0; event_storage->nest_level = 0; dblock->internal_data = (void *)(event_storage); /* Prepare the configuration data block */ if((error = init_config(dblock))) { DEBUG_NUMBER("Failed to init config",error); free(dblock->internal_data); dblock->internal_data = NULL; return error; } DEBUG_NUMBER("DBLOCK in init",dblock); DEBUG_NUMBER("internal data in init",dblock->internal_data); DEBUG_STRING("file_sink_init","Exit"); return EOK; } /* Formatting calback */ static int file_sink_format(struct data_descriptor *dblock, char *format_str, struct collection_item *event) { struct serial_data *serialized_data; int error = EOK; DEBUG_STRING("file_sink_format","Entry"); DEBUG_NUMBER("DBLOCK in format",dblock); DEBUG_NUMBER("internal data in format",dblock->internal_data); serialized_data = (struct serial_data *)(dblock->internal_data); if(format_str != NULL) { /* Use format string */ DEBUG_STRING("Using format:",format_str); error = serialize_with_format(event,format_str,serialized_data); } else { /* Traverse collection */ DEBUG_STRING("Using default serialization callback",""); error = traverse_collection(event,ELAPI_TRAVERSE_DEFAULT | ELAPI_TRAVERSE_END ,serialize,(void *)(serialized_data)); } if(error) { DEBUG_NUMBER("Serialization returned error",error); return error; } DEBUG_STRING("stderr_sink_format","Exit"); return EOK; } /* Cleanup per event internal data after a failure */ static void file_sink_cleanup(struct data_descriptor *dblock) { struct serial_data *event_storage; DEBUG_STRING("file_sink_cleanup","Entry"); event_storage = (struct serial_data *)(dblock->internal_data); if(event_storage->buffer != NULL) { free(event_storage->buffer); event_storage->buffer = NULL; event_storage->size = 0; event_storage->length = 0; event_storage->nest_level = 0; } DEBUG_STRING("file_sink_cleanup","Exit"); } /* Close facility */ static void file_sink_close(struct data_descriptor *dblock) { struct file_conf *conf_data; DEBUG_STRING("file_sink_close","Entry"); if(dblock->internal_data != NULL) { file_sink_cleanup(dblock); free(dblock->internal_data); dblock->internal_data=NULL; } if(dblock->config != NULL) { conf_data = (struct file_conf *)(dblock->config); if((conf_data->file_name != NULL) && (conf_data->keep_open != 0)) { close(conf_data->file); } if(conf_data->file_name != NULL) free(conf_data->file_name); free(dblock->config); dblock->config=NULL; } DEBUG_STRING("file_sink_close","Exit"); } /* Logging calback */ static int file_sink_submit(struct data_descriptor *dblock) { struct serial_data *event_storage; struct file_conf *conf_data; DEBUG_STRING("file_sink_submit","Entry"); DEBUG_NUMBER("DBLOCK in submit",dblock); DEBUG_NUMBER("internal data in submit",dblock->internal_data); event_storage = (struct file_event *)(dblock->internal_data); conf_data = (struct file_conf *)(dblock->config); DEBUG_STRING("OUTPUT:",event_storage->buffer); if((conf_data->file_name != NULL) && (conf_data->keep_open == 0)) { conf_data->file = fopen(conf_data->file_name,"w"); } fprintf(conf_data->file, "%s\n", event_storage->buffer); if((conf_data->file_name != NULL) && (conf_data->keep_open == 0)) { close(conf_data->file); } file_sink_cleanup(dblock); DEBUG_STRING("file_sink_submit","Exit"); return EOK; } /* Return a filled in structure */ void get_sink_info(struct sink_capability *sink_cpb_block) { DEBUG_STRING("get_sink_info","Entry"); sink_cpb_block->retry_interval = FILE_RETRY; sink_cpb_block->flags = SINK_FLAG_NO_LIMIT; sink_cpb_block->instance = 0; sink_cpb_block->init_cb = file_sink_init; sink_cpb_block->cleanup_cb = file_sink_cleanup; sink_cpb_block->format_cb = file_sink_format; sink_cpb_block->submit_cb = file_sink_submit; sink_cpb_block->close_cb = file_sink_close; DEBUG_STRING("get_sink_info","Exit"); }