From 8fb404ff3d803964764452f7e027ded5bf1d85b3 Mon Sep 17 00:00:00 2001 From: Dmitri Pal Date: Thu, 26 Feb 2009 16:32:20 -0500 Subject: Major changes. Added high level API. Unstable. Checkin before testing. --- collection/elapi_collection.c | 229 ++++++++++++++++++++- collection/elapi_collection.h | 29 ++- collection/elapi_util.c | 411 ++++++++++++++++++++++++++++++++++++++ collection/elapi_util.h | 5 + configure.ac | 2 +- dispatcher/Makefile.am | 2 +- dispatcher/elapi_dispatcher.c | 19 +- dispatcher/elapi_dispatcher.h | 34 +++- dispatcher/elapi_dispatcher_ut.c | 136 +++++++++++-- etc/file_defaults.conf | 0 etc/file_defaults.d/my_app1.conf | 8 + etc/file_defaults.d/my_app1.conf~ | 8 + etc/file_defaults.d/my_app2.conf | 8 + etc/file_defaults.d/my_app2.conf~ | 17 ++ sinks/Makefile.am | 2 +- sinks/elapi_sink.h | 2 +- sinks/file/Makefile.am | 4 +- sinks/file/elapi_sink_file.c | 269 +++++++++++-------------- sinks/stderr/elapi_sink_stderr.c | 18 +- sinks/syslog/elapi_sink_syslog.c | 44 ++-- 20 files changed, 1036 insertions(+), 211 deletions(-) create mode 100644 etc/file_defaults.conf create mode 100644 etc/file_defaults.d/my_app1.conf create mode 100644 etc/file_defaults.d/my_app1.conf~ create mode 100644 etc/file_defaults.d/my_app2.conf create mode 100644 etc/file_defaults.d/my_app2.conf~ diff --git a/collection/elapi_collection.c b/collection/elapi_collection.c index 50809ae..7045130 100644 --- a/collection/elapi_collection.c +++ b/collection/elapi_collection.c @@ -35,6 +35,13 @@ /* Special internal error code to indicate that collection search was interrupted */ #define EINTR_INTERNAL 10000 + +/* Potential subjest for management with libtools */ +#define DATE_FORMAT "%+" + +#define TIME_ARRAY_SIZE 100 + + /* Struct used for passing parameter for update operation */ struct update_property { int type; @@ -712,10 +719,10 @@ static int update_item(struct collection_item *current, int error = EOK; DEBUG_STRING("update_item","Entry"); - /* If type is different or samew but it is string or binary we need to replace the storage */ + /* If type is different or same but it is string or binary we need to replace the storage */ if((current->type != update_data->type) || ((current->type == update_data->type) && - ((current->type != ELAPI_TYPE_STRING) || (current->type != ELAPI_TYPE_BINARY)))) { + ((current->type == ELAPI_TYPE_STRING) || (current->type == ELAPI_TYPE_BINARY)))) { DEBUG_STRING("Replacing item data buffer",""); free(current->data); current->data = malloc(update_data->length); @@ -1174,6 +1181,224 @@ int add_any_property(struct collection_item *ci, return error; } +/* Add a string property. + If length equals 0, the length is determined based on the string. + Lenght INCLUDES the terminating 0 */ +int add_str_property_with_ref(struct collection_item *ci,char *subcollection, char *property,char *string,int length, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_str_property_with_ref","Entry."); + + if(length == 0) length = strlen(string) + 1; + item = add_property(ci,subcollection,property,(void *)(string),length, ELAPI_TYPE_STRING, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_str_property_with_ref returning",error); + return error; +} + +/* Add a binary property. */ +int add_binary_property_with_ref(struct collection_item *ci,char *subcollection, char *property,void *binary_data,int length, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_binary_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,binary_data,length, ELAPI_TYPE_BINARY, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_binary_property_with_ref returning",error); + return error; +} + +/* Add an int property. */ +int add_int_property_with_ref(struct collection_item *ci,char *subcollection, char *property,int number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_int_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(int), ELAPI_TYPE_INTEGER, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_int_property_with_ref returning",error); + return error; +} + +/* Add an unsigned int property. */ +int add_unsigned_property_with_ref(struct collection_item *ci,char *subcollection, char *property,unsigned int number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_unsigned_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(int), ELAPI_TYPE_UNSIGNED, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_unsigned_property_with_ref returning",error); + return error; +} + +/* Add an long property. */ +int add_long_property_with_ref(struct collection_item *ci,char *subcollection, char *property,long number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_long_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(long), ELAPI_TYPE_LONG, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_long_property_with_ref returning",error); + return error; +} + +/* Add an unsigned long property. */ +int add_ulong_property_with_ref(struct collection_item *ci,char *subcollection, char *property,unsigned long number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_ulong_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(long), ELAPI_TYPE_ULONG, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_ulong_property_with_ref returning",error); + return error; +} + +/* Add a double property. */ +int add_double_property_with_ref(struct collection_item *ci,char *subcollection, char *property,double number, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_double_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,(void *)(&number),sizeof(double), ELAPI_TYPE_DOUBLE, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_double_property_with_ref returning",error); + return error; +} + +/* A function to add a property */ +int add_any_property_with_ref(struct collection_item *ci, + char *subcollection, + char *property, + int type, + void *data, + int length, + struct collection_item **ref_ret) +{ + int error = EOK; + struct collection_item *item; + + DEBUG_STRING("add_any_property_with_ref","Entry."); + + item = add_property(ci,subcollection,property,data,length, type, &error); + + if(ref_ret != (struct collection_item **)(NULL)) *ref_ret = item; + + DEBUG_NUMBER("add_any_property_with_ref returning",error); + return error; +} + +/* Set time stamp in the collection */ +int set_timestamp(struct collection_item *ci,struct collection_item **timestr_ref,struct collection_item **timeint_ref) +{ + time_t utctime; + struct tm time_struct; + char time_array[TIME_ARRAY_SIZE+1]; + int len; + struct collection_item *timestr = (struct collection_item *)(NULL); + struct collection_item *timeint = (struct collection_item *)(NULL); + + DEBUG_STRING("set_timestamp","Entry point"); + + utctime = time(NULL); + localtime_r(&utctime,&time_struct); + + len = strftime(time_array, TIME_ARRAY_SIZE, date_format, &time_struct); + if(len == 0) { + DEBUG_STRING("add_time","CODING ERROR - INCREASE THE BUFFER"); + return EMSGSIZE; + } + + /* Check if we have the timestamp item already */ + error = get_item(event, TS_NAME, ELAPI_TYPE_STRING,ELAPI_TRAVERSE_IGNORE,×tr); + if(error) { + DEBUG_NUMBER("search failed with error:",error); + return error; + } + + if(timestr != (struct collection_item *)(NULL)) { + /* There is a timestamp */ + free(timestr->data); + timestr->data = strdup(time_array); + if(timestr->data == NULL) { + DEBUG_NUMBER("failed to add timestamp property:",error); + return ENOMEM; + } + timestr->length = len+1; + *timestr_ref = timestr; + } + else { + /* Add timestamp to the collection */ + error = add_str_property_with_ref(event,NULL, TS_NAME,time_array,len+1,timestr_ref); + if(error) { + DEBUG_NUMBER("failed to add timestamp property:",error); + return error; + } + } + + /* Check if we have the time item already */ + error = get_item(event, T_NAME, ELAPI_TYPE_INTEGER,ELAPI_TRAVERSE_IGNORE,&timeint); + if(error) { + DEBUG_NUMBER("search failed with error:",error); + return error; + } + + if(timeint != (struct collection_item *)(NULL)) { + /* There is a time property */ + *((int *)(timeint->data)) = utctime; + *timeint_ref = timeint; + } + else { + /* Add time to the collection */ + error = add_int_property_with_ref(event,NULL, T_NAME,utctime,timeint_ref); + if(error) { + DEBUG_NUMBER("failed to add time property:",error); + return error; + } + } + + DEBUG_STRING("set_timestamp","Exit point"); + return EOK; +} + + /* COPY */ diff --git a/collection/elapi_collection.h b/collection/elapi_collection.h index 361c0c6..1451484 100644 --- a/collection/elapi_collection.h +++ b/collection/elapi_collection.h @@ -55,6 +55,10 @@ #define ELAPI_TRAVERSE_END 0x00000002 /* Call handler once more when end of the collection is reached - good for processing nested collections */ #define ELAPI_TRAVERSE_IGNORE 0x00000004 /* Ignore sub collections at all as if there are none */ +/* Time stamp property name */ +#define TS_NAME "timestamp" +/* Time property name */ +#define T_NAME "time" /* Match values */ #define ELAPI_NOMATCH 0 @@ -110,6 +114,29 @@ int add_any_property(struct collection_item *ci, /* Collection to find things void *data, /* Pointer to the new data */ int length); /* Length of the data. For strings should include trailing 0 */ +/* The functions that add an item and immediately return you this item in the ret_ref paramter */ +int add_str_property_with_ref(struct collection_item *ci,char *subcollection, char *property,char *string,int length, + struct collection_item **ret_ref); +int add_binary_property_with_ref(struct collection_item *ci,char *subcollection, char *property,void *binary_data,int length, + struct collection_item **ret_ref); +int add_int_property_with_ref(struct collection_item *ci,char *subcollection, char *property,int number, + struct collection_item **ret_ref); +int add_unsigned_property_with_ref(struct collection_item *ci,char *subcollection, char *property,unsigned int number, + struct collection_item **ret_ref); +int add_long_property_with_ref(struct collection_item *ci,char *subcollection, char *property,long number, + struct collection_item **ret_ref); +int add_ulong_property_with_ref(struct collection_item *ci,char *subcollection, char *property,unsigned long number, + struct collection_item **ret_ref); +int add_double_property_with_ref(struct collection_item *ci,char *subcollection, char *property,double number, + struct collection_item **ret_ref); +int add_any_property_with_ref(struct collection_item *ci,char *subcollection,char *property,int type,void *data,int length, + struct collection_item **ret_ref); + +/* Function to create a timestamp */ +/* Automatically adds/updates time and timestamp properties in the collection returning references */ +int set_timestamp(struct collection_item *ci, + struct collection_item **timestr_ref, + struct collection_item **timeint_ref); /* Update functions */ @@ -192,7 +219,7 @@ int get_item_and_do(struct collection_item *ci, /* Collection to find thin /* Convenience function to get individual item */ /* Caller should be aware that this is not a copy of the item * but the pointer to actual item stored in the collection. - * The retuned pointer should never be altered or freed by caller of the function. + * The returned pointer should never be altered or freed by caller of the function. * The caller should be sure that the collection does not go out of scope * while the pointer to its data is in use. */ int get_item(struct collection_item *ci, /* Collection to find things in */ diff --git a/collection/elapi_util.c b/collection/elapi_util.c index e275703..b5fbf59 100644 --- a/collection/elapi_util.c +++ b/collection/elapi_util.c @@ -26,6 +26,23 @@ #include "elapi_debug.h" #include "elapi_util.h" + +/* Internal defines used in different places */ +#define UNKNOWN "" +#define UNKNOWN_LEN sizeof(UNKNOWN)-1 +#define BAD_FORMAT "" +#define BAD_FORMAT_LEN sizeof(BAD_FORMAT)-1 + +#define FMT_STRING 0 +#define FMT_INTEGER 1 +#define FMT_UNSIGNED 2 +#define FMT_LONG 3 +#define FMT_ULONG 4 +#define FMT_DOUBLE 5 + +#define TIMESTAMP "(" TS_NAME ")" +#define TIMESTAMP_LEN sizeof(TS_NAME) + 1 + /* Return a static string based on type of the element */ const char *get_type(int type) { @@ -515,3 +532,397 @@ int xml_add(char *property, return EOK; } + + +/* Extracet and lookup item */ +static int extract_item(char *start, + struct collection_item *event, + struct collection_item **item, + int *index) +{ + char *end; + + DEBUG_STRING("extract_item","Entry point"); + + start++; + end = start; + while((*end != ')') && (*end != '\0')) end++; + + if(*end == '\0') return EINVAL; + + *end = '\0'; + error = get_item(event,start,ELAPI_TYPE_ANY, + ELAPI_TRAVERSE_DEFAULT,item); + *end = ')'; + *index += (end-start)+1; + + DEBUG_STRING("extract_item","Exit point"); + return error; +} + + +/* Function to serialize one item using provided format if any */ +int sprintf_item(struct serial_data *data, + struct collection_item *item, + char *one_format) +{ + int len; + int length; + int error = EOK; + int i; + int len_format = 0; + char *formats[] = {"\"%s\"","%d","%u","%ld","%lu","%.4f"}; + char *fmt; + int block; + char *start; + + DEBUG_STRING("sprintf_item","Entry point"); + + DEBUG_NUMBER("Buffer len: ", data->length); + DEBUG_NUMBER("Buffer size: ", data->size); + DEBUG_STRING("Buffer: ", data->buffer); + + + if(one_format!=NULL) len_format = strlen(one_format); + + /* Handle special binary case - ignore format for it */ + if(item->type == ELAPI_TYPE_BINARY) { + /* Bake sure we have enough memory */ + if((error=grow_buffer(data,item->length * 2 + 2))) return error; + /* Put opening quote */ + *(data->buffer+data->length) = '\''; + data->length++; + for(i=0;ilength;i++) sprintf(data->buffer+data->length+i*2,"%02X",*((unsigned char *)(item->data+i))); + data->length+=item->length*2; + *(buf_data->buffer+buf_data->length) = '\''; + buf_data->length++ + *(buf_data->buffer+buf_data->length) = '\0'; + } + else { + + /* For other types use a version of sprintf, but determine format first */ + switch(item->type) { + case ELAPI_TYPE_STRING: if((len_format > 0) && (*(one_format+len_format-1) == 's') fmt=one_format; + else fmt = formats[FMT_STRING]; + break; + case ELAPI_TYPE_INTEGER: if((len_format > 0) && (*(one_format+len_format-1) != 's')) fmt=one_format; + else fmt = formats[FMT_INTEGER]; + break; + case ELAPI_TYPE_UNSIGNED: if((len_format > 0) && (*(one_format+len_format-1) != 's')) fmt=one_format; + else fmt = formats[FMT_UNSIGNED]; + break; + case ELAPI_TYPE_LONG: if((len_format > 0) && (*(one_format+len_format-1) != 's')) fmt=one_format; + else fmt = formats[FMT_LONG]; + break; + case ELAPI_TYPE_ULONG: if((len_format > 0) && (*(one_format+len_format-1) != 's')) fmt=one_format; + else fmt = formats[FMT_ULONG]; + break; + case ELAPI_TYPE_DOUBLE: if((len_format > 0) && + (*(one_format+len_format-1) != 's') && + (*(one_format+len_format-1) != 'c')) fmt=one_format; + else fmt = formats[FMT_INTEGER]; + break; + default: + /* In case we do not know the type */ + error = put_marker(data,UNKNOWN,UNKNOWN_LEN); + if(error) { + DEBUG_NUMBER("put_marker returned error:",error); + return error; + } + error = put_marker(data,item->property,item->property_len); + if(error) { + DEBUG_NUMBER("put_marker returned error:",error); + return error; + } + DEBUG_STRING("sprintf_item","Unknown item exit point"); + return EOK; + } + + start = buf_data->buffer+buf_data->length; + block = buf_data->size-buf_data->length-1; + + while (1) { + switch(item->type) { + case ELAPI_TYPE_STRING: len = snprintf(start,block, + fmt, (char *)(item->data)); + break; + case ELAPI_TYPE_INTEGER: len = snprintf(start,block, + fmt, *((int *)(item->data))); + break; + case ELAPI_TYPE_UNSIGNED: len = snprintf(start,block, + fmt, *((unsigned *)(item->data))); + break; + case ELAPI_TYPE_LONG: len = snprintf(start,block, + fmt, *((long *)(item->data))); + break; + case ELAPI_TYPE_ULONG: len = snprintf(start,block, + fmt, *((unsigned long *)(item->data))); + break; + case ELAPI_TYPE_DOUBLE: len = snprintf(start,block, + fmt, *((double *)(item->data))); + break; + default: /* Not possible */ + DEBUG_STRING("sprintf_item","Unknown item exit point 2."); + return EOK; + } + + /* Did it fit? */ + if (len > -1 && len < block) break; + + /* Else try again with more space. Based on printf example. */ + if (len > -1) block = MAX(n+1,BLOCK_SIZE); + else block = MAX(block *2,BLOCK_SIZE); + + if((error=grow_buffer(data,block))) return error; + } + + /* Adjust length */ + buf_data->length+=len; + *(buf_data->buffer+buf_data->length) = '\0'; + } + DEBUG_STRING("Data: ",buf_data->buffer); + DEBUG_STRING("sprintf_item","Exit point"); + return EOK; + +} + + +/* If time is missing add it */ +static int add_time(struct serial_data *data, + struct collection_item *event) +{ + struct collection_item *timestamp; + + DEBUG_STRING("add_time","Entry point"); + + error = set_timestamp(event,×tamp,NULL); + if(error) { + DEBUG_NUMBER("set_timestamp returned error:",error); + return error; + } + + error = put_marker(data,timestamp->data,timestamp->length-1); + if(error) { + DEBUG_NUMBER("put_marker returned error:",error); + return error; + } + + DEBUG_STRING("add_time","Exit point"); +} + + +/* Internal function to parse out item and put the item data based on the lookup */ +static int process_item(struct serial_data *data, + char *format_str, + int *index, + struct collection_item *event, + char *one_format, + int *brk) +{ + char *start; + char *end; + int block; + struct collection_item *item = (struct collection_item *)(NULL); + + DEBUG_STRING("process_item","Entry point"); + + start = format_str + *index; + error = extract_item(start,event,&item,index); + if(error) { + /* This is a problem with format not with memory */ + error = put_marker(data,BAD_FORMAT,BAD_FORMAT_LEN); + if(error) { + DEBUG_NUMBER("put_marker bad format returned error:",error); + return error; + } + /* Bad format - we are done */ + *brk = 1; + } + else { + /* Check if item exists */ + if(item == (struct collection_item *)(NULL)) { + + if(strncmp(start,TIMESTAMP,TIMESTAMP_LEN) == 0) { + DEBUG_STRING("process_item","Adding time"); + /* Add a timestamp automatically */ + error = add_time(data,event); + + } + else { + /* We will put placeholder instead */ + error = put_marker(data,UNKNOWN,UNKNOWN_LEN); + if(error) { + DEBUG_NUMBER("put_marker returned error:",error); + return error; + } + + /* Then put the piece we could not find */ + error = put_marker(data,start+1,*index-(start-format_str)-2); + } + if(error) { + DEBUG_NUMBER("put_marker/add_time returned error:",error); + return error; + } + (*index)++; + DEBUG_STRING("Format after processing not found item:",format_str+*index); + } + else { + /* Item found - call sprintf_item using native format ! */ + error = sprintf_item(data,item,one_format); + if(error) { + DEBUG_NUMBER("sprintf_item returned error:",error); + return error; + } + (*index)++; + DEBUG_STRING("Format after processing item:",format_str+*index); + } + } + DEBUG_STRING("process_item","Exit"); + return EOK; +} + +#define CHECK_VALID(x) ((x == 'd')||(x == 'i')||(x == 'o')||(x == 'u')||\ + (x == 'x')||(x == 'X')||(x == 'c')||(x == 's')||\ + (x == 'e')||(x == 'E')||(x == 'g')||(x == 'G')||\ + (x == 'f')||(x == 'F')||(x == 'a')||(x == 'A')) + + +/* Serialize using format */ +int serialize_with_format(struct collection_item *event, + char *format_str, + struct serial_data *data) +{ + + int i=0; + char *one_format; + int brk; + + DEBUG_STRING("serialize_with_format","Entry point"); + + + /* Allocate output buffer */ + errno = 0; + data->buffer = malloc(BLOCK_SIZE); + if(data->buffer == NULL) { + DEBUG_NUMBER("Out of memory",errno); + return ENOMEM; + } + data->size = BLOCK_SIZE; + data->length = 0; + + /* Create buffer for format specifier */ + errno = 0; + one_format = malloc(len+1); + if(one_format == NULL) { + DEBUG_NUMBER("Out of memory",errno); + free(data->buffer); + data->buffer=NULL; + return ENOMEM; + } + + while(1) { + /* Copy characters directly into output */ + start = format_str+i; + end = start; + block = 0; + while((*end != '%') && (*end != '\0')) end++; + if(end > start) { + /* We have a block to copy to output buffer */ + block = end-start; + error = put_marker(data,start,block); + if(error) { + DEBUG_NUMBER("put_marker returned error:",error); + free(data->buffer); + data->buffer=NULL; + free(one_format); + return ENOMEM; + } + } + /* Check if we are done */ + if(*end == '\0') break; + + /* We are not done - we have %*/ + i+=block+1; + + /* Here we are at the beginning of the string after % */ + DEBUG_STRING("Format after %:",format_str+i); + + /* Handle special case */ + if(*(format_str+i) == '%') { + error = put_marker(data,"%",1); + if(error) { + DEBUG_NUMBER("put_marker returned error:",error); + free(data->buffer); + data->buffer=NULL; + free(one_format); + return error; + } + i++; + DEBUG_STRING("Format after processing %%:",format_str+i); + continue; + } + + /* We are here in case there is a real format token */ + if(*(format_str+i) == '(') { + /* This is our special case when we have a event item specifier () */ + brk = 0; + error = process_item(data,format_str,&i,event,NULL,&brk); + if(error) { + DEBUG_NUMBER("put_marker bad format returned error:",error); + free(data->buffer); + data->buffer=NULL; + free(one_format); + return error; + } + if(brk) break; + continue; + } + + /* There is a format specifier ! */ + start = format_str+i; + end = start; + block = 0; + while((*end != '(') && (*end != '\0')) end++; + + /* Check why we stopped */ + if((*end == '\0') || (!(CHECK_VALID(*(end-1))))) { + /* Someything is not right - put marker and we are done */ + error = put_marker(data,BAD_FORMAT,BAD_FORMAT_LEN); + if(error) { + DEBUG_NUMBER("put_marker bad format returned error:",error); + free(data->buffer); + data->buffer=NULL; + free(one_format); + return error; + } + /* We are done */ + break; + } + + /* We are here becuase we have a valid (hopefully) format */ + block = end - start - 1; + memcpy(one_format,start,block); + *(one_format+block) = '\0'; + + i = end - format_str; + brk = 0; + error = process_item(data,format_str,&i,event,one_format); + if(error) { + DEBUG_NUMBER("put_marker bad format returned error:",error); + free(data->buffer); + data->buffer=NULL; + free(one_format); + return error; + } + + if(brk) break; + DEBUG_STRING("Format after another item:",format_str+i); + } + + /* Out of the loop */ + DEBUG_STRING("serialize_with_format","Success Exit"); + return EOK; +} + + + diff --git a/collection/elapi_util.h b/collection/elapi_util.h index a379ec3..3c2a650 100644 --- a/collection/elapi_util.h +++ b/collection/elapi_util.h @@ -22,6 +22,7 @@ #define ELAPI_UTIL_H #include +#include "elapi_collection.h" #define DEFAULT_ENCODING "ISO-8859-1" @@ -90,5 +91,9 @@ int xml_add(char *property, void *custom_data, int *dummy); +/* Serialize using format */ +int serialize_with_format(struct collection_item *event, + char *format_str, + struct serial_data *data); #endif diff --git a/configure.ac b/configure.ac index a71ec1f..dbc36e1 100644 --- a/configure.ac +++ b/configure.ac @@ -12,7 +12,7 @@ DEBUG_VAR= AC_ARG_ENABLE([debug],[AS_HELP_STRING([--enable-debug],[enable debug build])],[],[debug_build=no]) AS_IF([test "x$debug_build" != xno],[AC_SUBST([DEBUG_VAR],[-DELAPI_LOG_DEBUG])]) -AC_CONFIG_FILES([Makefile collection/Makefile ini/Makefile sinks/Makefile sinks/stderr/Makefile sinks/syslog/Makefile dispatcher/Makefile ]) +AC_CONFIG_FILES([Makefile collection/Makefile ini/Makefile sinks/Makefile sinks/stderr/Makefile sinks/syslog/Makefile sinks/file/Makefile dispatcher/Makefile ]) AC_OUTPUT diff --git a/dispatcher/Makefile.am b/dispatcher/Makefile.am index ea5b5ff..0fbb031 100644 --- a/dispatcher/Makefile.am +++ b/dispatcher/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = -I$(srcdir)/../collection -I$(srcdir)/../sinks -I/usr/include/libx common_headers=elapi_collection.h elapi_debug.h elapi_tools.h elapi_dispatcher.h elapi_sink.h noinst_LIBRARIES = libelapi_dispatcher.a -libelapi_dispatcher_a_SOURCES = elapi_dispatcher.c $(common_headers) +libelapi_dispatcher_a_SOURCES = elapi_dispatcher.c elapi_api.c $(common_headers) noinst_PROGRAMS = elapi_dispatcher_ut elapi_dispatcher_ut_SOURCES = elapi_dispatcher_ut.c $(common_headers) diff --git a/dispatcher/elapi_dispatcher.c b/dispatcher/elapi_dispatcher.c index 3995310..27a3eca 100644 --- a/dispatcher/elapi_dispatcher.c +++ b/dispatcher/elapi_dispatcher.c @@ -28,10 +28,8 @@ #include "elapi_collection.h" #include "elapi_sink.h" -#define SINK_COLLECTION "sinks" - -char def_application_name[] = "unknown"; - +char sink_collection[] = "sinks"; +char def_application_name[] = "default"; char *default_sinks[] = { "ipa","kernel","syslog","file","stderr", NULL }; @@ -39,6 +37,7 @@ char *default_sinks[] = { "ipa","kernel","syslog","file","stderr", NULL }; struct sink_context { struct collection_item *event; struct dispatcher_handle *handle; + char *format; char *previous; int previous_status; }; @@ -374,6 +373,7 @@ static int sink_handler(char *sink, sink_env->previous, sink_env->previous_status, sink_env->event, + sink_env->format, sink_data, (sink_env->handle)->custom_data, &error); @@ -428,6 +428,7 @@ static int default_router(char *sink, char *previous_sink, int previous_status, struct collection_item *event, + char *format_string struct sink_descriptor *sink_data, void *custom_data, int *error) @@ -441,7 +442,7 @@ static int default_router(char *sink, */ - *error = log_event_to_sink(sink_data,event,custom_data); + *error = log_event_to_sink(sink_data,event,format_string,custom_data); @@ -462,7 +463,7 @@ static int construct_sink_list(struct dispatcher_handle *handle) DEBUG_STRING("construct_sink_list","Entry"); /* Allocate collection to store sinks */ - error=create_collection(&(handle->sink_list),SINK_COLLECTION); + error=create_collection(&(handle->sink_list),sink_collection); if(error != 0) { DEBUG_NUMBER("Failed to create sink collection. Error",error); /* No cleanup here. @@ -603,6 +604,7 @@ void destroy_audit_dispatcher(struct dispatcher_handle *dispatcher) /* Log evento into a specific sink */ int log_event_to_sink(struct sink_descriptor *sink_data, struct collection_item *event, + char *format_string, void *custom_data) { int error = EOK; @@ -617,7 +619,7 @@ int log_event_to_sink(struct sink_descriptor *sink_data, DEBUG_SINK(sink_data); /* Format (serialize the event) */ - error = sink_cpb->format_cb(&(sink_data->dblock),event); + error = sink_cpb->format_cb(&(sink_data->dblock),format_string,event); if(error != EOK) { DEBUG_NUMBER("Format function returned error",error); return error; @@ -637,7 +639,7 @@ int log_event_to_sink(struct sink_descriptor *sink_data, /* Function to clean memory associated with the audit dispatcher */ -void log_audit_event(struct dispatcher_handle *dispatcher, struct collection_item *event) +void log_audit_event(struct dispatcher_handle *dispatcher, char *format_str, struct collection_item *event) { struct sink_context sink_env; @@ -653,6 +655,7 @@ void log_audit_event(struct dispatcher_handle *dispatcher, struct collection_ite sink_env.handle = dispatcher; sink_env.event = event; + sink_env.format = format_str; /* Logging an event is just iterating through the sinks and calling the sink_handler */ (void)traverse_collection(dispatcher->sink_list,ELAPI_TRAVERSE_ONELEVEL,sink_handler,(void *)(&sink_env)); diff --git a/dispatcher/elapi_dispatcher.h b/dispatcher/elapi_dispatcher.h index c7a582e..c47e8ff 100644 --- a/dispatcher/elapi_dispatcher.h +++ b/dispatcher/elapi_dispatcher.h @@ -43,6 +43,7 @@ typedef int (*event_router_fn)(char *sink, char *previous_sink, int previous_status, struct collection_item *event, + char *format_string, struct sink_descriptor *sink_data, void *custom_data, int *error); @@ -56,6 +57,11 @@ struct dispatcher_handle { void *custom_data; }; +/******************** Low level thread safe interface ************************************/ +/* This interface should be used if application plans to control the dispatcher, + * implement its own sinks that can be added dynamically or implements it own routing finction. + */ + /* Function to create a dispatcher */ int create_audit_dispatcher(struct dispatcher_handle **dispatcher, /* Handle of the dispatcher will be stored in this variable */ const char *appname, /* Application name. Passed to the sinks to do initialization */ @@ -68,7 +74,7 @@ int create_audit_dispatcher(struct dispatcher_handle **dispatcher, /* Handle of void destroy_audit_dispatcher(struct dispatcher_handle *dispatcher); /* Function to log an event */ -void log_audit_event(struct dispatcher_handle *dispatcher, struct collection_item *event); +void log_audit_event(struct dispatcher_handle *dispatcher, char *format_string, struct collection_item *event); /* Advanced functions */ /* Managing the sink collection */ @@ -79,7 +85,33 @@ int alter_audit_dispatcher(struct dispatcher_handle *dispatcher, /* Dispatcher * /* This function is exposed in case you are providing your own routing callback */ int log_event_to_sink(struct sink_descriptor *sink_data, struct collection_item *event, + char *format_string, void *custom_data); +/******************** High level interface ************************************/ +/* This interface is not thread safe but hides the dispatcher. */ + +/* Function to open audit using default routing functions */ +/* If appname is NULL - uses module name */ +int open_audit(const char *appname, char **desired_sinks); + +/* Function to open audit using custom routing function */ +int open_audit_with_router(const char *appname, + char **desired_sinks, + event_router_fn desired_router, + void *custom_data); + +/* Log event */ +void log_event(char *format_string,struct collection_item *event); + +/* Get dispatcher if you want to add sink to a default deispatcher or do some advaced operations */ +struct dispatcher_handle *get_dispatcher(void); + +/* Close audit */ +void close_audit(void); + +/* Creates collection with the timestamp already prepopulated */ +int create_event(struct collection_item **event,char *name); + #endif diff --git a/dispatcher/elapi_dispatcher_ut.c b/dispatcher/elapi_dispatcher_ut.c index e860096..aa0a041 100644 --- a/dispatcher/elapi_dispatcher_ut.c +++ b/dispatcher/elapi_dispatcher_ut.c @@ -124,25 +124,102 @@ int construct_event() return EOK; } - -int main() +int high_level_test() { int error = EOK; struct dispatcher_handle *dispatcher; struct dispatcher_handle *dispatcher2; - char *sinks[]= { "foo", "stderr", "bar", NULL }; + char *sinks[]= { "foo", "stderr", "file", NULL }; + char bin[] = { '\1','\2','\3','\4','\5','\6','\7','\8' }; - printf("Test start\n"); + printf("High level test start\n"); + printf("%s","=================\nOpening audit\n"); + error = open_audit("my_app1",sinks); + if(error!) { + printf("open_audit returned %d\n", error); + return error; + } + else printf("Success : %d\n",error); - error = create_audit_dispatcher(&dispatcher,"my_app",sinks,NULL,NULL); - printf("create_audit_dispatcher returned %d\n", error); + printf("%s","=================\nAdding syslog - first time - expect success\n"); + error = alter_audit_dispatcher(get_dispatcher(),"syslog",ELAPI_SINK_ACTION_ADD); + if(error != 0) { + printf("Expected success got failure %d\n",error); + return error; + } + else printf("Success : %d\n",error); + + printf("%s","=================\nAdding syslog again\n"); + error = alter_audit_dispatcher(get_dispatcher(),"syslog",ELAPI_SINK_ACTION_ADD); + if(error == 0) { + printf("Expected failure got success %d\n",error); + return EINVAL; + } + else printf("Expected error : %d\n",error); + + printf("%s","=================\nAdding syslog - first time - expect success\n"); + error = alter_audit_dispatcher(get_dispatcher(),"foo",ELAPI_SINK_ACTION_DELETE); + if(error != 0) { + printf("Expected success got failure %d\n",error); + return error; + } + else printf("Success : %d\n",error); + + printf("%s","=================\nCreating collection\n"); + if((error=create_event(&event,"test_event")) || + (error=add_str_property(event,NULL,"name","some name",0)) || + (error=add_int_property(event,NULL,"number",-100)) || + (error=add_binary_property(event,NULL,"binary",bin,8)) || + (error=add_double_property(event,NULL,"double",3.141592))) { + printf("Failed to create collection. Error %d\n",error); + return error; + } + else printf("Success : %d\n",error); + + printf("%s","=================\nLog event using NULL format\n"); + log_event(NULL, event); + + printf("%s","=================\nLog event using First format\n"); + log_event("%(timestamp), %s(name), %(number), %(bin), %%, %e(double)", event); + + printf("%s","=================\nLog event using Second format\n"); + log_event("%08X(time), %50s(name), %u(number), %s(bin), %%, %A(double)", event); + + printf("%s","=================\nLog event using Third format\n"); + log_event("%-50s(timestamp), %50s(name), %lo(number), %a(bin), %%, %.8f(double)", event); - /* Try to log with invalid parameters */ - printf("%s","=================\nNegative test1\n"); - log_audit_event(NULL, NULL); - printf("%s","=================\nNegative test2\n"); - log_audit_event(dispatcher, NULL); + + printf("%s","=================\nNegative tests\n"); + printf("%s","=================\nLog event using Third format\n"); + log_event("%-50s(timestamp), %50s(name, %lo(number), %a(bin), %%, %.8f(double)", event); + log_event("%(times), %z(name), %lo(number), %a(bin), %%, %.8f(double)", event); + log_event("%(times), %(name ), %lo(number), %a(bin), %%, %.8f(double)", event); + log_event("%(times), (name ), %lo(number), %a(bin), %%, %.8f(double)", event); + log_event("%(times), (name ) %, %.8f(double)", event); + log_event("%(times), (name ) %f (double)", event); + + + destroy_collection(event); + close_audit(void); + + printf("Low level test end\n"); + return error; +} + + +int low_level_test() +{ + int error = EOK; + char *sinks[]= { "foo", "stderr", "bar", NULL }; + + printf("Low level test start\n"); + + error = create_audit_dispatcher(&dispatcher,"my_app",sinks,NULL,NULL); + if(error!) { + printf("create_audit_dispatcher returned %d\n", error); + return error; + } printf("%s","=================\nCreating collection\n"); error = construct_event(); @@ -154,16 +231,16 @@ int main() printf("%s","=================\nLogging peer - expect success\n"); print_collection(peer); - log_audit_event(dispatcher, peer); + log_audit_event(dispatcher, NULL, peer); printf("%s","=================\nLogging host - expect success\n"); print_collection(host); - log_audit_event(dispatcher, host); + log_audit_event(dispatcher, NULL, host); printf("%s","=================\nLogging socket - expect success\n"); print_collection(socket); - log_audit_event(dispatcher, socket); + log_audit_event(dispatcher, NULL, socket); printf("%s","=================\nLogging event - expect success\n"); print_collection(event); - log_audit_event(dispatcher, event); + log_audit_event(dispatcher, NULL, event); /* Try to alter list of sinks */ printf("%s","=================\nSeries of negative test cases.\n"); @@ -201,16 +278,16 @@ int main() /* Log event into syslog */ printf("%s","=================\nLogging peer - expect success\n"); print_collection(peer); - log_audit_event(dispatcher, peer); + log_audit_event(dispatcher, NULL, peer); printf("%s","=================\nLogging host - expect success\n"); print_collection(host); - log_audit_event(dispatcher, host); + log_audit_event(dispatcher, NULL, host); printf("%s","=================\nLogging socket - expect success\n"); print_collection(socket); - log_audit_event(dispatcher, socket); + log_audit_event(dispatcher, NULL, socket); printf("%s","=================\nLogging event - expect success\n"); print_collection(event); - log_audit_event(dispatcher, event); + log_audit_event(dispatcher, NULL, event); /* Pulse */ error = alter_audit_dispatcher(dispatcher,"syslog",ELAPI_SINK_ACTION_PULSE); @@ -251,7 +328,26 @@ int main() destroy_collection(host); destroy_collection(socket); destroy_collection(event); - printf("Test end\n"); + printf("Low level test end\n"); + return error; +} + + +int main() +{ + int error = EOK; + + error = low_level_test(); + printf("Low level test returned: %d\n",error); + if(error) return error; + + error = high_level_test(); + printf("High level test first run returned: %d\n",error); + if(error) return error; + + error = high_level_test(); + printf("High level test second run returned: %d\n",error); + return error; } diff --git a/etc/file_defaults.conf b/etc/file_defaults.conf new file mode 100644 index 0000000..e69de29 diff --git a/etc/file_defaults.d/my_app1.conf b/etc/file_defaults.d/my_app1.conf new file mode 100644 index 0000000..32cdfaf --- /dev/null +++ b/etc/file_defaults.d/my_app1.conf @@ -0,0 +1,8 @@ +; This is the test application configuration +; Log into the given file: + +file_name=/tmp/log1 + +; Open once and keep open (default is 1) + +keep_open=1 diff --git a/etc/file_defaults.d/my_app1.conf~ b/etc/file_defaults.d/my_app1.conf~ new file mode 100644 index 0000000..33f860c --- /dev/null +++ b/etc/file_defaults.d/my_app1.conf~ @@ -0,0 +1,8 @@ +; This is the test application configuration +; Log into the given file: + +file_name=/tmp/log1 + +; Open once and keep open + +keep_open=1 diff --git a/etc/file_defaults.d/my_app2.conf b/etc/file_defaults.d/my_app2.conf new file mode 100644 index 0000000..da3a8a0 --- /dev/null +++ b/etc/file_defaults.d/my_app2.conf @@ -0,0 +1,8 @@ +; This is the test application configuration +; Log into the given file: + +file_name=/tmp/log2 + +; Open once and keep open (default is 1) + +keep_open=0 diff --git a/etc/file_defaults.d/my_app2.conf~ b/etc/file_defaults.d/my_app2.conf~ new file mode 100644 index 0000000..fe5846a --- /dev/null +++ b/etc/file_defaults.d/my_app2.conf~ @@ -0,0 +1,17 @@ +; This is the test application configuration +; Identify myself as "TESTAPP" +; See /usr/include/sys/syslog.h for more details + +identity="TESTAPP" + +; Default option is to include PID + +option = 1 + +; Level is LOG_INFO. + +level = 6 + +; Facility is LOG_AUTHPRIV (upper 28 bits) 10<<3 + +facility = 80 diff --git a/sinks/Makefile.am b/sinks/Makefile.am index 125e373..97f6410 100644 --- a/sinks/Makefile.am +++ b/sinks/Makefile.am @@ -1 +1 @@ -SUBDIRS = stderr syslog +SUBDIRS = stderr syslog file diff --git a/sinks/elapi_sink.h b/sinks/elapi_sink.h index 74b7622..8a8db37 100644 --- a/sinks/elapi_sink.h +++ b/sinks/elapi_sink.h @@ -46,7 +46,7 @@ struct data_descriptor { /* Log facility callbacks */ typedef int (*init_fn)(struct data_descriptor *dblock); typedef void (*cleanup_fn)(struct data_descriptor *dblock); -typedef int (*format_fn)(struct data_descriptor *dblock, struct collection_item *event); +typedef int (*format_fn)(struct data_descriptor *dblock, char *format_str, struct collection_item *event); typedef int (*submit_fn)(struct data_descriptor *dblock); typedef void (*close_fn)(struct data_descriptor *dblock); diff --git a/sinks/file/Makefile.am b/sinks/file/Makefile.am index 67b3ca2..cf61012 100644 --- a/sinks/file/Makefile.am +++ b/sinks/file/Makefile.am @@ -3,7 +3,7 @@ DEBUG_FLAGS=@DEBUG_VAR@ AM_CPPFLAGS = -I$(srcdir)/.. -I$(srcdir)/../../collection -I$(srcdir)/../../ini -I/usr/include/libxml2 $(DEBUG_FLAGS) -lib_LTLIBRARIES = libelapi_sink_syslog.la -libelapi_sink_syslog_la_SOURCES = elapi_sink_syslog.c $(topdir)/ini/elapi_ini.c +lib_LTLIBRARIES = libelapi_sink_file.la +libelapi_sink_file_la_SOURCES = elapi_sink_file.c $(topdir)/ini/elapi_ini.c include_HEADERS = ../elapi_sink.h diff --git a/sinks/file/elapi_sink_file.c b/sinks/file/elapi_sink_file.c index 057bb34..660aba3 100644 --- a/sinks/file/elapi_sink_file.c +++ b/sinks/file/elapi_sink_file.c @@ -27,17 +27,14 @@ #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 FILE_RETRY 60 /* -#define FILE_AUDIT_CONFIG "/etc/elapi/syslog_defaults.conf" -#define FILE_AUDIT_DIR "/etc/elapi/syslog_defaults.d" +#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/syslog_defaults.conf" -#define FILE_AUDIT_DIR "/home/dpal/IPA/Code/elapi/etc/syslog_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 @@ -49,114 +46,75 @@ static int instance = 0; */ -struct syslog_event { - struct serial_data sd; - int priority; -}; - - /* Default conmfiguration for syslog */ -struct syslog_conf { - int option; - int facility; - int level; - char *ident; +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 syslog_conf *conf_data; - struct collection_item *file_config = (struct collection_item *)(NULL); + struct file_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 *keep_open_cfg = (int *)(NULL); + char *file_name_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; + 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, SYSLOG_AUDIT_CONFIG, SYSLOG_AUDIT_DIR, &file_config); + (void)config_to_collection(dblock->appname, FILE_AUDIT_CONFIG, FILE_AUDIT_DIR, &config_from_file); - conf_data->option = LOG_ODELAY; - conf_data->facility = LOG_USER; - conf_data->level = LOG_INFO; - conf_data->ident = NULL; + conf_data->keep_open = 1; + conf_data->file_name = 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); + 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 *)(&option_cfg),ELAPI_TYPE_INTEGER, INI_DEFAULT_SECTION,"option",file_config); - if(error != EOK) { - /* There is fundamentally something wrong */ - DEBUG_NUMBER("Attempt to get option returned error",error); - 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",file_config); - if(error != EOK) { - /* There is fundamentally something wrong */ - DEBUG_NUMBER("Attempt to get option returned error",error); - 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",file_config); + 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(level_cfg != (int *)(NULL)) { - conf_data->level = *level_cfg; - free((void *)(level_cfg)); + if(keep_open_cfg != (int *)(NULL)) { + conf_data->keep_open = *keep_open_cfg; + free((void *)(keep_open_cfg)); } - error = get_value_from_config((void *)(&ident_cfg),ELAPI_TYPE_STRING, INI_DEFAULT_SECTION,"identity",file_config); + 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(ident_cfg != (char *)(NULL)) { - conf_data->ident = ident_cfg; + if(file_name_cfg != (char *)(NULL)) { + conf_data->file_name = file_name_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); + 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); - openlog(conf_data->ident,conf_data->option,conf_data->facility); - instance++; - DEBUG_NUMBER("syslog instance",instance); + if((conf_data->file_name != NULL) && (conf_data->keep_open != 0)) { + file_conf->file = fopen(conf_data->file_name,"w"); + } + else conf_data->file_name = stderr; DEBUG_STRING("init_config","Entry"); return EOK; @@ -164,23 +122,23 @@ static int init_config(struct data_descriptor *dblock) /***** Standard functions each facility has to provide *****/ /* Initialize facility - open files, establish connnectons, etc... */ -static int syslog_sink_init(struct data_descriptor *dblock) +static int file_sink_init(struct data_descriptor *dblock) { - struct syslog_event *event_storage; + struct serial_data *event_storage; int error; - DEBUG_STRING("syslog_sink_init","Entry"); + 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 syslog_event *)(malloc(sizeof(struct syslog_event))); - if(event_storage == (struct syslog_event *)(NULL)) return errno; + event_storage = (struct serail_data *)(malloc(sizeof(struct serial_data))); + if(event_storage == (struct serail_data *)(NULL)) return errno; - event_storage->sd.buffer = NULL; - event_storage->sd.size = 0; - event_storage->sd.length = 0; - event_storage->sd.nest_level = 0; + event_storage->buffer = NULL; + event_storage->size = 0; + event_storage->length = 0; + event_storage->nest_level = 0; dblock->internal_data = (void *)(event_storage); @@ -195,119 +153,122 @@ static int syslog_sink_init(struct data_descriptor *dblock) DEBUG_NUMBER("DBLOCK in init",dblock); DEBUG_NUMBER("internal data in init",dblock->internal_data); - DEBUG_STRING("syslog_sink_init","Exit"); + DEBUG_STRING("file_sink_init","Exit"); return EOK; } /* Formatting calback */ -static int syslog_sink_format(struct data_descriptor *dblock,struct collection_item *event) +static int file_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; + struct serial_data *serialized_data; int error = EOK; - DEBUG_STRING("syslog_sink_format","Entry"); + DEBUG_STRING("file_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); + serialized_data = (struct serial_data *)(dblock->internal_data); - 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)); - - - /* FIXME */ - - - /* Traverse collection */ - error = traverse_collection(event,ELAPI_TRAVERSE_DEFAULT | ELAPI_TRAVERSE_END ,serialize,(void *)(&(event_storage->sd))); + 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("traverse_collection returned error",error); + DEBUG_NUMBER("Serialization returned error",error); return error; } - DEBUG_STRING("syslog_sink_format","Exit"); + DEBUG_STRING("stderr_sink_format","Exit"); return EOK; } /* Cleanup per event internal data after a failure */ -static void syslog_sink_cleanup(struct data_descriptor *dblock) +static void file_sink_cleanup(struct data_descriptor *dblock) { - struct syslog_event *event_storage; - struct syslog_conf *config; + struct serial_data *event_storage; - DEBUG_STRING("syslog_sink_cleanup","Entry"); + DEBUG_STRING("file_sink_cleanup","Entry"); - event_storage = (struct syslog_event *)(dblock->internal_data); - config = (struct syslog_conf *)(dblock->config); + event_storage = (struct file_event *)(dblock->internal_data); - 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; + 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("syslog_sink_cleanup","Exit"); + DEBUG_STRING("file_sink_cleanup","Exit"); } /* Close facility */ -static void syslog_sink_close(struct data_descriptor *dblock) +static void file_sink_close(struct data_descriptor *dblock) { - struct syslog_conf *config; + struct file_conf *config; - DEBUG_STRING("syslog_sink_close","Entry"); + DEBUG_STRING("file_sink_close","Entry"); if(dblock->internal_data != NULL) { - syslog_sink_cleanup(dblock); + file_sink_cleanup(dblock); free(dblock->internal_data); - config = (struct syslog_conf *)(dblock->config); - if(config->ident != NULL) free(config->ident); - free(dblock->config); dblock->internal_data=NULL; + } + + if(dblock->config != NULL) { + config = (struct file_conf *)(dblock->config); + + if((conf_data->file_name != NULL) && (conf_data->keep_open != 0)) { + close(file_conf->file); + } + + if(config->file_name != NULL) free(config->file_name); + 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"); + DEBUG_STRING("file_sink_close","Exit"); } /* Logging calback */ -static int syslog_sink_submit(struct data_descriptor *dblock) +static int file_sink_submit(struct data_descriptor *dblock) { - struct syslog_event *event_storage; + struct serial_data *event_storage; + struct file_conf *config; - DEBUG_STRING("syslog_sink_submit","Entry"); + DEBUG_STRING("file_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); + event_storage = (struct file_event *)(dblock->internal_data); + config = (struct file_conf *)(dblock->config); - DEBUG_STRING("OUTPUT:",event_storage->sd.buffer); + DEBUG_STRING("OUTPUT:",event_storage->buffer); + + if((conf_data->file_name != NULL) && (conf_data->keep_open == 0)) { + file_conf->file = fopen(conf_data->file_name,"w"); + } - syslog(event_storage->priority, "%s", event_storage->sd.buffer); + fprintf(file_conf->file, "%s\n", event_storage->buffer); + + if((conf_data->file_name != NULL) && (conf_data->keep_open == 0)) { + close(file_conf->file); + } - syslog_sink_cleanup(dblock); + file_sink_cleanup(dblock); - DEBUG_STRING("syslog_sink_submit","Exit"); + DEBUG_STRING("file_sink_submit","Exit"); return EOK; } @@ -316,14 +277,14 @@ 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; + 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"); } diff --git a/sinks/stderr/elapi_sink_stderr.c b/sinks/stderr/elapi_sink_stderr.c index 7bd5bf8..1c56b4e 100644 --- a/sinks/stderr/elapi_sink_stderr.c +++ b/sinks/stderr/elapi_sink_stderr.c @@ -59,7 +59,9 @@ static int stderr_sink_init(struct data_descriptor *dblock) /* Formatting calback */ -static int stderr_sink_format(struct data_descriptor *dblock,struct collection_item *event) +static int stderr_sink_format(struct data_descriptor *dblock, + char *format_str, + struct collection_item *event) { struct serial_data *serialized_data; int error = EOK; @@ -70,10 +72,18 @@ static int stderr_sink_format(struct data_descriptor *dblock,struct collection_i serialized_data = (struct serial_data *)(dblock->internal_data); - /* Traverse collection */ - error = traverse_collection(event,ELAPI_TRAVERSE_DEFAULT | ELAPI_TRAVERSE_END ,serialize,(void *)(serialized_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("traverse_collection returned error",error); + DEBUG_NUMBER("Serialization returned error",error); return error; } diff --git a/sinks/syslog/elapi_sink_syslog.c b/sinks/syslog/elapi_sink_syslog.c index e1500b5..eb1585e 100644 --- a/sinks/syslog/elapi_sink_syslog.c +++ b/sinks/syslog/elapi_sink_syslog.c @@ -68,7 +68,7 @@ struct syslog_conf { static int init_config(struct data_descriptor *dblock) { struct syslog_conf *conf_data; - struct collection_item *file_config = (struct collection_item *)(NULL); + struct collection_item *config_from_file = (struct collection_item *)(NULL); int found = 0; int *option_cfg = (int *)(NULL); int *facility_cfg = (int *)(NULL); @@ -83,7 +83,7 @@ static int init_config(struct data_descriptor *dblock) 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, &file_config); + (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; @@ -96,10 +96,11 @@ static int init_config(struct data_descriptor *dblock) 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",file_config); + 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); + DEBUG_NUMBER("Attempt to get option returned error",error); + free((void *)(conf_data)); return error; } @@ -109,10 +110,11 @@ static int init_config(struct data_descriptor *dblock) free((void *)(option_cfg)); } - error = get_value_from_config((void *)(&facility_cfg),ELAPI_TYPE_INTEGER, INI_DEFAULT_SECTION,"facility",file_config); + 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; } @@ -122,10 +124,11 @@ static int init_config(struct data_descriptor *dblock) free((void *)(facility_cfg)); } - error = get_value_from_config((void *)(&level_cfg),ELAPI_TYPE_INTEGER, INI_DEFAULT_SECTION,"level",file_config); + 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; } @@ -135,10 +138,11 @@ static int init_config(struct data_descriptor *dblock) free((void *)(level_cfg)); } - error = get_value_from_config((void *)(&ident_cfg),ELAPI_TYPE_STRING, INI_DEFAULT_SECTION,"identity",file_config); + 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; } @@ -202,7 +206,9 @@ static int syslog_sink_init(struct data_descriptor *dblock) /* Formatting calback */ -static int syslog_sink_format(struct data_descriptor *dblock,struct collection_item *event) +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; @@ -228,13 +234,18 @@ static int syslog_sink_format(struct data_descriptor *dblock,struct collection_i event_storage->priority = *((int *)(item->data)); - /* FIXME */ - - - /* Traverse collection */ - error = traverse_collection(event,ELAPI_TRAVERSE_DEFAULT | ELAPI_TRAVERSE_END ,serialize,(void *)(&(event_storage->sd))); + 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("traverse_collection returned error",error); + DEBUG_NUMBER("Serialization returned error",error); return error; } @@ -276,10 +287,13 @@ static void syslog_sink_close(struct data_descriptor *dblock) 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->internal_data=NULL; dblock->config=NULL; } -- cgit