/* ELAPI Module implements high level API for logging events Copyright (C) Dmitri Pal 2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include "elapi_debug.h" #include "elapi_dispatcher.h" #include "elapi_collection.h" #include "elapi_sink.h" char event_name[] = "event"; /* Pointer to default global dispatcher */ struct dispatcher_handle *global_dispatcher = (struct dispatcher_handle *)(NULL); /* Function to open audit using default routing functions */ /* If appname is NULL - uses module name */ int open_audit(const char *appname, char **desired_sinks) { int error; DEBUG_STRING("open_audit","Entry"); error = create_audit_dispatcher(&global_dispatcher,appname,desired_sinks,NULL,NULL); DEBUG_NUMBER("open_audit Exit:",error); return error; } /* 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) { int error; DEBUG_STRING("open_audit_with_router","Entry"); error = create_audit_dispatcher(&global_dispatcher,appname,desired_sinks,desired_router,custom_data); DEBUG_NUMBER("open_audit_with_router Exit:",error); return error; } /* Get dispatcher if you want to add sink to a default deispatcher or do some advaced operations */ struct dispatcher_handle *get_dispatcher(void) { DEBUG_STRING("get_dispatcher was called.","Returning default dispatcher."); return global_dispatcher; } /* Close audit */ void close_audit(void) { DEBUG_STRING("close_audit","Entry"); destroy_audit_dispatcher(global_dispatcher); DEBUG_STRING("close_audit","Exit"); } /* Creates collection with the timestamp already prepopulated */ int create_event(struct collection_item **event,char *name) { int error; char *nm; DEBUG_STRING("create_event","Entry"); if(name == NULL) nm = event_name; else nm = name; /* Construct collection and add timestamp */ if(((error = create_collection(event,nm)) != 0) || ((error = set_timestamp(*event,NULL,NULL)) !=0 )) { DEBUG_NUMBER("Failed to create event:",error); return error; } DEBUG_STRING("create_event Exit:",""); return EOK; } /* Internal untility function to tokenize a string */ static char *get_next_property(char *cursor,int *type, char **property, int *has_len) { int adjust_by; char *start; DEBUG_STRING("get_next_property","Entry"); DEBUG_STRING("Cursor",cursor); /* Initialize passed in data */ *has_len = 0; *property = NULL; *type = ELAPI_TYPE_STRING; while((*cursor != '\0') && (*cursor != '%')) cursor++; /* End of string - we are done */ if(*cursor == '\0') { DEBUG_STRING("End of format - returning.",""); return NULL; } /* This is the beginning of the formatted token */ cursor++; if((*cursor == '*') && (*(cursor+1) == 's') && (*(cursor+2) == '(')) { *type = ELAPI_TYPE_STRING; *has_len = 1; adjust_by = 3; } else if((*cursor == 's') && (*(cursor+1) == '(')) { *type = ELAPI_TYPE_STRING; adjust_by = 2; } else if(((*cursor == 'i')||(*cursor == 'd')) && (*(cursor+1) == '(')) { *type = ELAPI_TYPE_INTEGER; adjust_by = 2; } else if((*cursor == 'u') && (*(cursor+1) == '(')) { *type = ELAPI_TYPE_INTEGER; adjust_by = 2; } else if((*cursor == 'l') && ((*(cursor+1) == 'i')||(*(cursor+1) == 'd')) && (*(cursor+2) == '(')) { *type = ELAPI_TYPE_LONG; adjust_by = 3; } else if((*cursor == 'l') && (*(cursor+1) == 'u') && (*(cursor+2) == '(')) { *type = ELAPI_TYPE_LONG; adjust_by = 3; } else if(((*cursor == 'f')||(*cursor == 'e')) && (*(cursor+1) == '(')) { *type = ELAPI_TYPE_DOUBLE; adjust_by = 2; } else if((*cursor == 'b') && (*(cursor+1) == '(')) { *type = ELAPI_TYPE_BINARY; adjust_by = 2; } else { DEBUG_STRING("Invalid type specifier format:",cursor); return cursor; } cursor += adjust_by; start = cursor; /* Now we need to extruct the name of the property */ /* We will not be nice here - the add_property will validate if the name is ok */ while((*cursor != '\0') && (*cursor != ')')) cursor++; /* End of string - we are done */ if((*cursor == '\0') || (cursor==start)) { DEBUG_STRING("Bad property",""); return cursor; } *cursor ='\0'; *property = start; *cursor++; DEBUG_STRING("Returning Property:",*property); DEBUG_NUMBER("Returning Type:",*type); DEBUG_NUMBER("Returning Has length:",*has_len); DEBUG_STRING("get_next_property","Exit"); return cursor; } /* Creates collection - event based on the specified format */ int construct_event(struct collection_item **event,char *name, char *format, ...) { int error; char *dup_fmt; char *cursor; int type; char *property; int has_len; va_list args; char *data_str; int data_int; unsigned int data_uint; long data_long; unsigned long data_ulong; void *data_bin; double data_dbl; int length; void *data; DEBUG_STRING("constuct_event","Entry"); /* Create event with timestamp */ error = create_event(event,name); if(error) { DEBUG_NUMBER("create_event returned error:",error); return error; } /* Format is omitted just return */ if(format == NULL) { DEBUG_STRING("constuct_event","NULL format exit"); return EOK; } /* Process the format */ /* Duplicate it */ errno = 0; dup_fmt = strdup(format); if(dup_fmt == NULL) { error = errno; DEBUG_NUMBER("Failed to dup format:",error); destroy_collection(*event); return ENOMEM; } va_start(args,format); cursor = dup_fmt; while((cursor = get_next_property(cursor,&type,&property,&has_len)) != NULL) { /* Handle the case when the parsing failed */ if(property == NULL) { DEBUG_STRING("Error parsing:",dup_fmt); free(dup_fmt); destroy_collection(*event); va_end(args); return error; } /* Get data */ switch(type) { case ELAPI_TYPE_STRING: data_str = va_arg(args,char *); data = (void *)data_str; if(has_len) length = va_arg(args,int); else length = strlen(data_str)+1; DEBUG_STRING("Adding string:",data_str); DEBUG_NUMBER("Length:",length); break; case ELAPI_TYPE_BINARY: data_bin = va_arg(args,void *); data = (void *)data_bin; length = va_arg(args,int); break; case ELAPI_TYPE_INTEGER: data_int = va_arg(args,int); data = (void *)(&data_int); length = sizeof(int); break; case ELAPI_TYPE_UNSIGNED: data_uint = va_arg(args,unsigned int); data = (void *)(&data_uint); length = sizeof(unsigned int); break; case ELAPI_TYPE_LONG: data_long = va_arg(args,long); data = (void *)(&data_long); length = sizeof(long); break; case ELAPI_TYPE_ULONG: data_ulong = va_arg(args,unsigned long); data = (void *)(&data_ulong); length = sizeof(unsigned long); break; case ELAPI_TYPE_DOUBLE: data_dbl = va_arg(args,double); data = (void *)(&data_dbl); length = sizeof(double); break; default: DEBUG_NUMBER("Unknown type",type); continue; } /* Add property to the event */ error = add_any_property(*event, NULL, property, type, data,length); if(error) { DEBUG_STRING("Error adding property:",property); DEBUG_NUMBER("Type :",type); DEBUG_NUMBER("Length :",length); free(dup_fmt); destroy_collection(*event); va_end(args); return error; } } va_end(args); free(dup_fmt); DEBUG_STRING("constuct_event","NULL format exit"); return EOK; } /* Add/Updates the event properties based on the format */ int modify_event(struct collection_item *event, int update, char *format, ...) { int error; char *dup_fmt; char *cursor; int type; char *property; int has_len; va_list args; char *data_str; int data_int; unsigned int data_uint; long data_long; unsigned long data_ulong; void *data_bin; double data_dbl; int length; void *data; DEBUG_STRING("modify_event","Entry"); /* Format is omitted just return */ if(format == NULL) { DEBUG_STRING("modify_event","NULL format exit"); return EOK; } /* Process the format */ /* Duplicate it */ errno = 0; dup_fmt = strdup(format); if(dup_fmt == NULL) { error = errno; DEBUG_NUMBER("Failed to dup format:",error); return ENOMEM; } va_start(args,format); cursor = dup_fmt; while((cursor = get_next_property(cursor,&type,&property,&has_len)) != NULL) { /* Handle the case when the parsing failed */ if(property == NULL) { DEBUG_STRING("Error parsing:",dup_fmt); free(dup_fmt); va_end(args); return error; } /* Get data */ switch(type) { case ELAPI_TYPE_STRING: data_str = va_arg(args,char *); data = (void *)data_str; if(has_len) length = va_arg(args,int); else length = strlen(data_str)+1; DEBUG_STRING("Modifying string:",data_str); DEBUG_NUMBER("Length:",length); break; case ELAPI_TYPE_BINARY: data_bin = va_arg(args,void *); data = (void *)data_bin; length = va_arg(args,int); break; case ELAPI_TYPE_INTEGER: data_int = va_arg(args,int); data = (void *)(&data_int); length = sizeof(int); break; case ELAPI_TYPE_UNSIGNED: data_uint = va_arg(args,unsigned int); data = (void *)(&data_uint); length = sizeof(unsigned int); break; case ELAPI_TYPE_LONG: data_long = va_arg(args,long); data = (void *)(&data_long); length = sizeof(long); break; case ELAPI_TYPE_ULONG: data_ulong = va_arg(args,unsigned long); data = (void *)(&data_ulong); length = sizeof(unsigned long); break; case ELAPI_TYPE_DOUBLE: data_dbl = va_arg(args,double); data = (void *)(&data_dbl); length = sizeof(double); break; default: DEBUG_NUMBER("Unknown type",type); continue; } /* Try to update property first but only on the high level */ if(update) { error = update_property(event, property, type, data, length, ELAPI_TRAVERSE_IGNORE); if(error == ENOENT) error = add_any_property(event, NULL, property, type, data,length); } else error = add_any_property(event, NULL, property, type, data,length); if(error) { DEBUG_STRING("Error adding/updating property:",property); DEBUG_NUMBER("Type :",type); DEBUG_NUMBER("Length :",length); free(dup_fmt); va_end(args); return error; } } va_end(args); DEBUG_STRING("modify_event","NULL format exit"); return EOK; } /* Log event */ void log_event(char *format_string,struct collection_item *event) { DEBUG_STRING("log_event","Entry"); log_audit_event(global_dispatcher, format_string, event); DEBUG_STRING("log_event","Entry"); }