/* ELAPI Implemenation of the syslog 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" /* Global variable - instance */ static int instance = 0; /* FIXME - this should be taken from the config.h generated by autotools */ #define SYSLOG_RETRY 60 /* #define SYSLOG_AUDIT_CONFIG "/etc/elapi/syslog_defaults.conf" #define SYSLOG_AUDIT_DIR "/etc/elapi/syslog_defaults.d" */ #define SYSLOG_AUDIT_CONFIG "/home/dpal/IPA/Code/elapi/etc/syslog_defaults.conf" #define SYSLOG_AUDIT_DIR "/home/dpal/IPA/Code/elapi/etc/syslog_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. */ struct syslog_event { struct serial_data sd; int priority; }; /* Default conmfiguration for syslog */ struct syslog_conf { int option; int facility; int level; char *ident; }; /* Internal function to intialize configuration */ static int init_config(struct data_descriptor *dblock) { struct syslog_conf *conf_data; struct collection_item *config_from_file = (struct collection_item *)(NULL); int found = 0; int *option_cfg = (int *)(NULL); int *facility_cfg = (int *)(NULL); int *level_cfg = (int *)(NULL); char *ident_cfg = NULL; int error; DEBUG_STRING("init_config","Entry"); /* Allocate configuration data */ conf_data = (struct syslog_conf *)(malloc(sizeof(struct syslog_conf))); if(conf_data == (struct syslog_conf *)(NULL)) return errno; /* Read configuration from the configuration file if any */ (void)config_to_collection(dblock->appname, SYSLOG_AUDIT_CONFIG, SYSLOG_AUDIT_DIR, &config_from_file); conf_data->option = LOG_ODELAY; conf_data->facility = LOG_USER; conf_data->level = LOG_INFO; conf_data->ident = NULL; DEBUG_NUMBER("Option",conf_data->option); DEBUG_NUMBER("Facility",conf_data->facility); DEBUG_NUMBER("Level",conf_data->level); DEBUG_STRING("Identity",conf_data->ident); /* Update defaults with settings from the file */ error = get_value_from_config((void *)(&option_cfg),ELAPI_TYPE_INTEGER, INI_DEFAULT_SECTION,"option",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(option_cfg != (int *)(NULL)) { conf_data->option = *option_cfg; free((void *)(option_cfg)); } error = get_value_from_config((void *)(&facility_cfg),ELAPI_TYPE_INTEGER, INI_DEFAULT_SECTION,"facility",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(facility_cfg != (int *)(NULL)) { conf_data->facility = *facility_cfg; free((void *)(facility_cfg)); } error = get_value_from_config((void *)(&level_cfg),ELAPI_TYPE_INTEGER, INI_DEFAULT_SECTION,"level",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(level_cfg != (int *)(NULL)) { conf_data->level = *level_cfg; free((void *)(level_cfg)); } error = get_value_from_config((void *)(&ident_cfg),ELAPI_TYPE_STRING, INI_DEFAULT_SECTION,"identity",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(ident_cfg != (char *)(NULL)) { conf_data->ident = ident_cfg; } DEBUG_NUMBER("Option (after conf file):",conf_data->option); DEBUG_NUMBER("Facility (after conf file):",conf_data->facility); DEBUG_NUMBER("Level (after conf file):",conf_data->level); DEBUG_STRING("Identity (after conf file):",conf_data->ident); dblock->config = (void *)(conf_data); openlog(conf_data->ident,conf_data->option,conf_data->facility); instance++; DEBUG_NUMBER("syslog instance",instance); DEBUG_STRING("init_config","Entry"); return EOK; } /***** Standard functions each facility has to provide *****/ /* Initialize facility - open files, establish connnectons, etc... */ static int syslog_sink_init(struct data_descriptor *dblock) { struct syslog_event *event_storage; int error; DEBUG_STRING("syslog_sink_init","Entry"); /* Prepare the block where the format function will store its data */ errno = 0; dblock->internal_data = NULL; event_storage = (struct syslog_event *)(malloc(sizeof(struct syslog_event))); if(event_storage == (struct syslog_event *)(NULL)) return errno; event_storage->sd.buffer = NULL; event_storage->sd.size = 0; event_storage->sd.length = 0; event_storage->sd.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("syslog_sink_init","Exit"); return EOK; } /* Formatting calback */ static int syslog_sink_format(struct data_descriptor *dblock, char *format_str, struct collection_item *event) { struct syslog_event *event_storage; struct syslog_conf *config; struct collection_item *item; int error = EOK; DEBUG_STRING("syslog_sink_format","Entry"); DEBUG_NUMBER("DBLOCK in format",dblock); DEBUG_NUMBER("internal data in format",dblock->internal_data); event_storage = (struct syslog_event *)(dblock->internal_data); config = (struct syslog_conf *)(dblock->config); event_storage->priority = config->level | config->facility; /* Get Priority */ error = get_item(event,"priority",ELAPI_TYPE_INTEGER,ELAPI_TRAVERSE_ONELEVEL, &item); if(error) { DEBUG_NUMBER("Failed to get item from collection",error); /* Fall through */ } else if((item != (struct collection_item *)(NULL)) && (item->type == ELAPI_TYPE_INTEGER)) event_storage->priority = *((int *)(item->data)); if(format_str != NULL) { /* Use format string */ DEBUG_STRING("Using format:",format_str); error = serialize_with_format(event,format_str,(void *)(&(event_storage->sd))); } else { /* Traverse collection */ DEBUG_STRING("Using default serialization callback",""); error = traverse_collection(event,ELAPI_TRAVERSE_DEFAULT | ELAPI_TRAVERSE_END ,serialize,(void *)(&(event_storage->sd))); } if(error) { DEBUG_NUMBER("Serialization returned error",error); return error; } DEBUG_STRING("syslog_sink_format","Exit"); return EOK; } /* Cleanup per event internal data after a failure */ static void syslog_sink_cleanup(struct data_descriptor *dblock) { struct syslog_event *event_storage; struct syslog_conf *config; DEBUG_STRING("syslog_sink_cleanup","Entry"); event_storage = (struct syslog_event *)(dblock->internal_data); config = (struct syslog_conf *)(dblock->config); if(event_storage->sd.buffer != NULL) { free(event_storage->sd.buffer); event_storage->sd.buffer = NULL; event_storage->sd.size = 0; event_storage->sd.length = 0; event_storage->sd.nest_level = 0; event_storage->priority = config->level | config->facility; } DEBUG_STRING("syslog_sink_cleanup","Exit"); } /* Close facility */ static void syslog_sink_close(struct data_descriptor *dblock) { struct syslog_conf *config; DEBUG_STRING("syslog_sink_close","Entry"); if(dblock->internal_data != NULL) { syslog_sink_cleanup(dblock); free(dblock->internal_data); dblock->internal_data=NULL; } if(dblock->config != NULL) { config = (struct syslog_conf *)(dblock->config); if(config->ident != NULL) free(config->ident); free(dblock->config); dblock->config=NULL; } closelog(); DEBUG_STRING("Closed syslog",""); if(instance) instance--; DEBUG_NUMBER("syslog instance",instance); DEBUG_STRING("syslog_sink_close","Exit"); } /* Logging calback */ static int syslog_sink_submit(struct data_descriptor *dblock) { struct syslog_event *event_storage; DEBUG_STRING("syslog_sink_submit","Entry"); DEBUG_NUMBER("DBLOCK in submit",dblock); DEBUG_NUMBER("internal data in submit",dblock->internal_data); event_storage = (struct syslog_event *)(dblock->internal_data); DEBUG_STRING("OUTPUT:",event_storage->sd.buffer); syslog(event_storage->priority, "%s", event_storage->sd.buffer); syslog_sink_cleanup(dblock); DEBUG_STRING("syslog_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 = SYSLOG_RETRY; sink_cpb_block->flags = SINK_FLAG_LOAD_SINGLE; sink_cpb_block->instance = instance; sink_cpb_block->init_cb = syslog_sink_init; sink_cpb_block->cleanup_cb = syslog_sink_cleanup; sink_cpb_block->format_cb = syslog_sink_format; sink_cpb_block->submit_cb = syslog_sink_submit; sink_cpb_block->close_cb = syslog_sink_close; DEBUG_STRING("get_sink_info","Exit"); }