summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitri Pal <dpal@redhat.com>2009-02-26 16:32:20 -0500
committerDmitri Pal <dpal@redhat.com>2009-02-26 16:32:20 -0500
commit8fb404ff3d803964764452f7e027ded5bf1d85b3 (patch)
tree472d7b69f545208fc54780fa8dbfcef1b6f4eb70
parentacb92e98ab01d5582d52737a7ad89919a00458aa (diff)
downloadelapi_draft-8fb404ff3d803964764452f7e027ded5bf1d85b3.tar.gz
elapi_draft-8fb404ff3d803964764452f7e027ded5bf1d85b3.tar.xz
elapi_draft-8fb404ff3d803964764452f7e027ded5bf1d85b3.zip
Major changes. Added high level API. Unstable. Checkin before testing.
-rw-r--r--collection/elapi_collection.c229
-rw-r--r--collection/elapi_collection.h29
-rw-r--r--collection/elapi_util.c411
-rw-r--r--collection/elapi_util.h5
-rw-r--r--configure.ac2
-rw-r--r--dispatcher/Makefile.am2
-rw-r--r--dispatcher/elapi_dispatcher.c19
-rw-r--r--dispatcher/elapi_dispatcher.h34
-rw-r--r--dispatcher/elapi_dispatcher_ut.c136
-rw-r--r--etc/file_defaults.conf0
-rw-r--r--etc/file_defaults.d/my_app1.conf8
-rw-r--r--etc/file_defaults.d/my_app1.conf~8
-rw-r--r--etc/file_defaults.d/my_app2.conf8
-rw-r--r--etc/file_defaults.d/my_app2.conf~17
-rw-r--r--sinks/Makefile.am2
-rw-r--r--sinks/elapi_sink.h2
-rw-r--r--sinks/file/Makefile.am4
-rw-r--r--sinks/file/elapi_sink_file.c269
-rw-r--r--sinks/stderr/elapi_sink_stderr.c18
-rw-r--r--sinks/syslog/elapi_sink_syslog.c44
20 files changed, 1036 insertions, 211 deletions
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,&timestr);
+ 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 "<unknown:>"
+#define UNKNOWN_LEN sizeof(UNKNOWN)-1
+#define BAD_FORMAT "<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;i<item->length;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,&timestamp,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 <libxml/xmlwriter.h>
+#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
--- /dev/null
+++ b/etc/file_defaults.conf
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;
}