diff options
Diffstat (limited to 'elapi/elapi_event.c')
-rw-r--r-- | elapi/elapi_event.c | 1112 |
1 files changed, 1112 insertions, 0 deletions
diff --git a/elapi/elapi_event.c b/elapi/elapi_event.c new file mode 100644 index 0000000..9322f82 --- /dev/null +++ b/elapi/elapi_event.c @@ -0,0 +1,1112 @@ +/* + ELAPI + + Implementation of the ELAPI event interface. + + Copyright (C) Dmitri Pal <dpal@redhat.com> 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 <http://www.gnu.org/licenses/>. +*/ + +#define _GNU_SOURCE +#include <sys/types.h> /* for getpid() */ +#include <unistd.h> /* for getpid() */ +#include <stdlib.h> /* for realloc() */ +#include <syslog.h> /* for contants releted to severity */ +#include <unistd.h> /* for gethostname() */ +#include <errno.h> /* for errors */ +#include <string.h> /* for memset() and other */ +#include <netdb.h> /* for gethostbyname() */ +#include <sys/socket.h> /* for inet_ntop() */ +#include <arpa/inet.h> /* for inet_ntop() */ +#include <ctype.h> /* for isspace() */ +#include <stdarg.h> /* for va_arg() */ +#include <string.h> /* for strndup() */ +#include <ifaddrs.h> /* for getifaddrs() */ + +#include "elapi_priv.h" +#include "elapi_event.h" +#include "trace.h" +#include "config.h" + +#include "collection_tools.h" + +/* Internal return states from key processing */ +#define E_LIST_EMPTY 0 +#define E_LIST_ERROR 1 +#define E_LIST_LAST 2 +#define E_LIST_ADD 3 +#define E_LIST_REMOVE 4 + +#define LOCALHOSTDOMAIN "localhost.localdomain" +#define LOCALHOST "localhost" +#define LOCALADDRESS "127.0.0.1" +#define LOCALADDRESSV6 "::1" + +const char *undefined = "undefined"; +const char *str_yes = "yes"; +const char *str_no = "no"; +const char *str_true = "true"; +const char *str_false = "false"; + +/* Default event template */ +struct collection_item *default_template = NULL; + + +/* Function to add host identity information to the template */ +int add_host_identity(struct collection_item *tpl, unsigned base) +{ + char hostname[NI_MAXHOST + 1]; + int error = EOK; + int gai_ret_host = 0; + int gai_ret_addr = 0; + char host[NI_MAXHOST]; + char address[NI_MAXHOST]; + char *hnm, *haddr; + struct ifaddrs *ifaddr, *ifa; + int family; + int set_hostname = 0; + int set_ip = 0; + + TRACE_FLOW_STRING("add_host_identity", "Entry"); + + memset(hostname, 0, sizeof(hostname)); + + /* The goal here to collect information about the host. + * there is no need to actually use it for establishing + * any connections. + * It is a best effort attempt. + */ + + /* If we are not asked for hostname then say we already have it */ + if (!(base & E_HAVE_HOSTNAME)) set_hostname = 1; + /* If we are not asked for ip then say we already have it */ + if (!(base & E_HAVE_HOSTIP)) set_ip = 1; + + if (getifaddrs(&ifaddr) == 0) { + + TRACE_FLOW_STRING("getifaddrs", "Ok"); + + /* Walk through linked list, maintaining head pointer so we + can free list later */ + + ifa = ifaddr; + while (ifa != NULL) { + + TRACE_FLOW_STRING("Top of the loop", ""); + + if (!ifa->ifa_addr) { + ifa = ifa->ifa_next; + continue; + } + + family = ifa->ifa_addr->sa_family; + + TRACE_FLOW_NUMBER("Family", family); + + /* For an AF_INET* interface address, display the address */ + if (family == AF_INET || family == AF_INET6) { + + TRACE_FLOW_NUMBER("Got right family", family); + /* Make sure the address is cleared - will help in comparisons */ + memset(host, 0, sizeof(host)); + memset(address, 0, sizeof(address)); + + gai_ret_host = getnameinfo(ifa->ifa_addr, + (family == AF_INET) ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6), + host, + NI_MAXHOST, + NULL, + 0, + 0 /* Gets host name */); + + gai_ret_addr = getnameinfo(ifa->ifa_addr, + (family == AF_INET) ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6), + address, + NI_MAXHOST, + NULL, + 0, + NI_NUMERICHOST /* Gets address as string */); + + /* If we have not set host name set it */ + if(!set_hostname) { + + TRACE_FLOW_STRING("Host name is not set", ""); + + hnm = NULL; + /* Use host name returned by gethostname() as main host name */ + if (!gethostname(hostname, NI_MAXHOST)) hnm = hostname; + else { + /* We we able to get a host name ? */ + if (gai_ret_host == 0) { + TRACE_INFO_STRING("getnameinfo returned:", host); + hnm = host; + } + } + + /* Do we have a host meaningful host name? */ + if ((hnm) && + ((strncasecmp(hnm, LOCALHOST, sizeof(LOCALHOST)) == 0 ) || + (strncasecmp(hnm, LOCALHOSTDOMAIN, sizeof(LOCALHOSTDOMAIN)) == 0 ) || + (strncasecmp(hnm, address, sizeof(address) == 0)))) hnm = NULL; + + /* If host name is not NULL it would work for us */ + if (hnm) { + TRACE_INFO_STRING("Adding host name:", hnm); + error = col_add_str_property(tpl, NULL, E_HOSTNAME, hnm, 0); + if (error) { + TRACE_ERROR_NUMBER("Failed to add host name. Error", error); + freeifaddrs(ifaddr); + return error; + } + /* Done with the name */ + set_hostname = 1; + } + } + + /* If we have not set processed ip address do it */ + if(!set_ip) { + + TRACE_FLOW_STRING("Address is not set", ""); + + haddr = NULL; + if (gai_ret_addr == 0) { + TRACE_INFO_STRING("getnameinfo returned:", address); + if ((strncasecmp(address, LOCALADDRESS, sizeof(LOCALADDRESS)) != 0 ) && + (strncasecmp(address, LOCALADDRESSV6, sizeof(LOCALADDRESSV6)) != 0 )) { + TRACE_INFO_STRING("Not an unhelpful address", ""); + haddr = address; + } + } + + if (haddr) { + TRACE_INFO_STRING("Adding host address:", haddr); + error = col_add_str_property(tpl, NULL, E_HOSTIP, haddr, 0); + if (error) { + TRACE_ERROR_NUMBER("Failed to add host name. Error", error); + freeifaddrs(ifaddr); + return error; + } + set_ip = 1; + } + } + + /* If we have a name and we are told to deal with alias names */ + if ((set_hostname) && (base & E_HAVE_HOSTALIAS)) { + + TRACE_INFO_NUMBER("gai_ret_host:", gai_ret_host); + TRACE_INFO_STRING("host:", host); + TRACE_INFO_STRING("address:", address); + TRACE_INFO_STRING("they are:", strncasecmp(host, address, sizeof(address)) == 0 ? "same" : "different"); + + /* Do we have a host meaningful host name? */ + if ((gai_ret_host != 0) || + ((gai_ret_host == 0) && + ((strncasecmp(host, LOCALHOST, sizeof(LOCALHOST)) == 0 ) || + (strncasecmp(host, LOCALHOSTDOMAIN, sizeof(LOCALHOSTDOMAIN)) == 0 ) || + (strncasecmp(host, address, sizeof(address)) == 0)))) hnm = NULL; + else hnm = host; + + if (hnm) { + TRACE_INFO_STRING("Adding alias host name:", hnm); + error = col_add_str_property(tpl, NULL, E_HOSTALIAS, hnm, 0); + if (error) { + TRACE_ERROR_NUMBER("Failed to add host name. Error", error); + freeifaddrs(ifaddr); + return error; + } + } + } + + /* If we got then main IP and we are told to deal with opther IPs */ + if ((set_ip) && (base & E_HAVE_HOSTIPS)) { + + /* Do we have a host meaningful host name? */ + if ((gai_ret_addr != 0) || + ((gai_ret_addr == 0) && + ((strncasecmp(address, LOCALADDRESS, sizeof(LOCALADDRESS)) == 0 ) || + (strncasecmp(address, LOCALADDRESSV6, sizeof(LOCALADDRESSV6)) == 0 )))) haddr = address; + else haddr = address; + + if (haddr) { + TRACE_INFO_STRING("Adding alias host IP:", haddr); + error = col_add_str_property(tpl, NULL, E_HOSTIPS, haddr, 0); + if (error) { + TRACE_ERROR_NUMBER("Failed to add host name. Error", error); + freeifaddrs(ifaddr); + return error; + } + } + } + } + TRACE_INFO_NUMBER("Moving to next", ifa->ifa_next); + ifa = ifa->ifa_next; + TRACE_INFO_NUMBER("Moved to", ifa); + } + + freeifaddrs(ifaddr); + } + + /* Make sure that we really have the name after all */ + if (!set_hostname) { + TRACE_INFO_STRING("No host name using default:", undefined); + error = col_add_str_property(tpl, NULL, E_HOSTNAME, undefined, 0); + if (error) { + TRACE_ERROR_NUMBER("Failed to add host name. Error", error); + return error; + } + } + + /* Make sure that we really have the IP after all */ + if (!set_ip) { + TRACE_INFO_STRING("No host name using default:", undefined); + error = col_add_str_property(tpl, NULL, E_HOSTIP, undefined, 0); + if (error) { + TRACE_ERROR_NUMBER("Failed to add host name. Error", error); + return error; + } + } + + TRACE_FLOW_STRING("add_host_identity", "Exit"); + return error; +} + +/* Add base elements to template collection */ +static int add_base_elements(struct collection_item *tpl, unsigned base) +{ + int error = EOK; + int pass_base; + + TRACE_FLOW_STRING("add_base_elements", "Entry"); + + /* Populate the template using base */ + if (base & E_HAVE_TIMESTAMP) { + /* Value is the format string for strftime() */ + error = col_add_str_property(tpl, NULL, E_TIMESTAMP, E_TIMESTAMP_FORMAT, sizeof(E_TIMESTAMP_FORMAT)); + if (error) { + TRACE_ERROR_NUMBER("Failed to add timestamp. Error", error); + return error; + } + } + + if (base & E_HAVE_UTCTIME) { + /* Value does not matter */ + error = col_add_int_property(tpl, NULL, E_UTCTIME, 0); + if (error) { + TRACE_ERROR_NUMBER("Failed to add UTC time. Error", error); + return error; + } + } + + if (base & E_HAVE_PID) { + /* Value is the current pid */ + error = col_add_long_property(tpl, NULL, E_PID, (long)getpid()); + if (error) { + TRACE_ERROR_NUMBER("Failed to add pid. Error", error); + return error; + } + } + + if (base & E_HAVE_APPNAME) { + /* Value does not matter */ + error = col_add_str_property(tpl, NULL, E_APPNAME, "", 1); + if (error) { + TRACE_ERROR_NUMBER("Failed to add application name. Error", error); + return error; + } + } + + if (base & E_HAVE_SEVERITY) { + /* Value is the default severity */ + error = col_add_int_property(tpl, NULL, E_SEVERITY, LOG_USER | LOG_INFO); + if (error) { + TRACE_ERROR_NUMBER("Failed to add pid. Error", error); + return error; + } + } + + /* If we need to add aliases or other IPs call the function */ + if ((base & E_HAVE_HOSTNAME) || + (base & E_HAVE_HOSTIP) || + (base & E_HAVE_HOSTALIAS) || + (base & E_HAVE_HOSTIPS)) { + + pass_base = base; + + /* make sure we have extensions on top of the basic data */ + if ((base & E_HAVE_HOSTALIAS) && (!(base & E_HAVE_HOSTNAME))) pass_base |= E_HAVE_HOSTNAME; + if ((base & E_HAVE_HOSTIPS) && (!(base & E_HAVE_HOSTIP))) pass_base |= E_HAVE_HOSTIP; + + error = add_host_identity(tpl, pass_base); + if (error) { + TRACE_ERROR_NUMBER("Failed to add host identity. Error", error); + return error; + } + } + + TRACE_FLOW_STRING("add_base_elements", "Exit"); + return error; +} + + +/* Internal untility function to tokenize a string */ +static int interprete_key(char *key, + int *type, + char **property, + int *prop_len, + int *has_len, + int *bool_type) +{ + int adjust_by = 0; + char *start = NULL; + char *cursor = NULL; + char *end = NULL; + int ret = E_LIST_EMPTY; + + TRACE_FLOW_STRING("interprete_key", "Entry"); + + TRACE_INFO_STRING("Key", key); + + /* Initialize passed in data */ + *has_len = 0; + *property = NULL; + *type = COL_TYPE_STRING; + + cursor = key; + + while (isspace(*cursor)) cursor++; + + /* End of string - we are done */ + if (*cursor == '\0') { + TRACE_ERROR_STRING("Empty key - end of processing!", ""); + return E_LIST_EMPTY; + } + + /* This is the beginning of the formatted token */ + if (*cursor == '-') { + + /* This is a remove attribute case */ + + cursor++; + /* Skip spaces if any */ + while (isspace(*cursor)) cursor++; + + /* Mark the start of the actual property */ + start = cursor; + + /* Now we need to extract the name of the property */ + /* We will not be nice here - the add_property will validate if the name is ok */ + while ((*cursor != '\0') && (!isspace(*cursor))) cursor++; + + /* End of string - we are done */ + if (cursor == start) { + TRACE_ERROR_STRING("Invalid key - end of processing!", ""); + return E_LIST_EMPTY; + } + + *prop_len = cursor - start; + *property = start; + TRACE_INFO_STRING("We are told to remove the property!", *property); + ret = E_LIST_REMOVE; + } + else if (*cursor == '%') { + + /* We got a full key with format string */ + + cursor++; + if ((*cursor == '*') && (*(cursor+1) == 's') && (*(cursor+2) == '(')) { + *type = COL_TYPE_STRING; + *has_len = 1; + adjust_by = 3; + } + else if ((*cursor == 's') && (*(cursor+1) == '(')) { + *type = COL_TYPE_STRING; + adjust_by = 2; + } + else if (((*cursor == 'i')||(*cursor == 'd')) && (*(cursor+1) == '(')) { + *type = COL_TYPE_INTEGER; + adjust_by = 2; + } + else if ((*cursor == 'u') && (*(cursor+1) == '(')) { + *type = COL_TYPE_INTEGER; + adjust_by = 2; + } + else if ((*cursor == 'l') && ((*(cursor+1) == 'i')||(*(cursor+1) == 'd')) && (*(cursor+2) == '(')) { + *type = COL_TYPE_LONG; + adjust_by = 3; + } + else if ((*cursor == 'l') && (*(cursor+1) == 'u') && (*(cursor+2) == '(')) { + *type = COL_TYPE_LONG; + adjust_by = 3; + } + else if (((*cursor == 'f')||(*cursor == 'e')) && (*(cursor+1) == '(')) { + *type = COL_TYPE_DOUBLE; + adjust_by = 2; + } + else if (((*cursor == 's') || (*cursor == 'd')) && (*(cursor+1) == 'b') && (*(cursor+2) == '(')) { + *type = COL_TYPE_BOOL; + adjust_by = 3; + if (*cursor == 's') *bool_type = 1; + else *bool_type = 0; + } + else if ((*cursor == 'n') && (*(cursor+1) == '(')) { + *type = COL_TYPE_BINARY; + adjust_by = 2; + } + else { + TRACE_ERROR_STRING("Invalid key - end of processing!", key); + return E_LIST_ERROR; + } + + cursor += adjust_by; + + /* Skip spaces if any */ + while (isspace(*cursor)) cursor++; + + start = cursor; + + /* Now we need to extract 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 != ')') && (!isspace(*cursor))) cursor++; + + /* End of string - we are done */ + if ((*cursor == '\0') || (cursor == start)) { + TRACE_ERROR_STRING("Invalid key - end of processing!", ""); + return E_LIST_EMPTY; + } + + end = cursor; + + /* Skip spaces if any */ + while (isspace(*cursor)) cursor++; + + /* Check that end of the string is in proper format */ + if ((*cursor != ')') && (*(cursor + 1) != '\0')) { + TRACE_ERROR_STRING("Invalid key - missing ')' .", key); + return E_LIST_ERROR; + } + + *property = start; + *prop_len = end - start; + + TRACE_INFO_STRING("Property:", *property); + TRACE_INFO_NUMBER("Property len:", *prop_len); + ret = E_LIST_ADD; + } + else { + /* Just got a key */ + /* Mark the start of the actual property */ + start = cursor; + + /* Now we need to extract the name of the property */ + /* We will not be nice here - the add_property will validate if the name is ok */ + while ((*cursor != '\0') && (!isspace(*cursor))) cursor++; + + /* End of string - we are done */ + if (cursor == start) { + TRACE_ERROR_STRING("Invalid key - end of processing!", ""); + return E_LIST_EMPTY; + } + + *prop_len = cursor - start; + *property = start; + TRACE_INFO_STRING("We are told to add/update the property (or last)!", *property); + + if(strncmp(*property, E_EOARG, *prop_len) == 0) ret = E_LIST_LAST; + else ret = E_LIST_ADD; + } + + TRACE_INFO_STRING("Returning Property:",*property); + TRACE_INFO_NUMBER("Returning Property len:", *prop_len); + TRACE_INFO_NUMBER("Returning Type:", *type); + TRACE_INFO_NUMBER("Returning Has length:", *has_len); + + + TRACE_FLOW_STRING("interprete_key", "Exit"); + + return ret; +} + +/* Make sure that the right string is given for bool value */ +static int convert_bool(char *data_str, unsigned char *data_bool) +{ + TRACE_FLOW_STRING("convert_bool", "Called"); + TRACE_INFO_STRING("Data", data_str); + + if ((strncasecmp(data_str, str_true, sizeof(str_true)) == 0) || + (strncasecmp(data_str, str_yes, sizeof(str_yes)) == 0)) { + TRACE_INFO_STRING("Matched TRUE", ""); + *data_bool = '\1'; + return 1; + } + if ((strncasecmp(data_str, str_false, sizeof(str_false)) == 0) || + (strncasecmp(data_str, str_no, sizeof(str_no)) == 0)) { + TRACE_INFO_STRING("Matched FALSE", ""); + *data_bool = '\0'; + return 1; + } + TRACE_INFO_STRING("Matched NOTHING", ""); + return 0; +} + + +/* Process argument list */ +/* Update collection based on the passed in arguments */ +static int process_arg_list(struct collection_item *col, + va_list args) +{ + int error = EOK; + char *arg = NULL; + char *propcopy = NULL; + int ret = 0; + int type = 0; + char *property = NULL; + int prop_len = 0; + int has_len = 0; + int bool_type = 0; + char *data_str = NULL; + int data_int = 0; + unsigned int data_uint = 0; + long data_long = 0; + unsigned long data_ulong = 0; + void *data_bin = NULL; + double data_dbl = 0.; + int length = 0; + void *data = NULL; + unsigned char data_bool = '\0'; + + TRACE_FLOW_STRING("process_arg_list", "Entry."); + + /* We will break from the loop when we find the last item */ + while (1) { + + /* Get next key */ + arg = va_arg(args, char *); + + if (arg == NULL) { + TRACE_ERROR_STRING("Invalid NULL argument.", "Key can't be NULL"); + return EINVAL; + } + + /* Interprete the key. + * It can be just " key ", + * it can be " - key ", + * or it can be a formatted string + * something like " %*s( key )". + * Function will deal with all cases. + * Passed in variables initialized and updated inside + */ + ret = interprete_key(arg, + &type, + &property, + &prop_len, + &has_len, + &bool_type); + + if (ret == E_LIST_LAST) { + TRACE_INFO_STRING("Process found last key", arg); + break; + } + + if ((ret == E_LIST_ADD) || (ret == E_LIST_REMOVE)) { + /* We need to create a dup of the string */ + propcopy = strndup(property, prop_len); + if (propcopy == NULL) { + TRACE_ERROR_STRING("Failed to allocate property", arg); + return ENOMEM; + } + + TRACE_INFO_STRING("Processing property", propcopy); + + /* Are we supposed to add? */ + if (ret == E_LIST_ADD) { + + + /* NOTE: We are not going to check if the key value pairs + * are consistent. + * It can be made a bit more bullet proof by adding + * significant complexity to the code but I do not + * think it makes much sense to do so. + * There is no way to prevent the argument mismatch + * issues 100%. Printf can crash if aguments are + * missed or bad, so do we... + */ + + /* Get data */ + switch(type) { + + case COL_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; + TRACE_INFO_STRING("Adding string:", data_str); + TRACE_INFO_NUMBER("Length:",length); + break; + + case COL_TYPE_BINARY: data_bin = va_arg(args, void *); + data = (void *)data_bin; + length = va_arg(args, int); + break; + + case COL_TYPE_INTEGER: data_int = va_arg(args, int); + data = (void *)(&data_int); + length = sizeof(int); + break; + + case COL_TYPE_UNSIGNED: data_uint = va_arg(args, unsigned int); + data = (void *)(&data_uint); + length = sizeof(unsigned int); + break; + + case COL_TYPE_LONG: data_long = va_arg(args, long); + data = (void *)(&data_long); + length = sizeof(long); + break; + + case COL_TYPE_ULONG: data_ulong = va_arg(args, unsigned long); + data = (void *)(&data_ulong); + length = sizeof(unsigned long); + break; + + case COL_TYPE_DOUBLE: data_dbl = va_arg(args, double); + data = (void *)(&data_dbl); + length = sizeof(double); + break; + + case COL_TYPE_BOOL: if (bool_type) { + /* It is a string */ + data_str = va_arg(args,char *); + /* Check if it is a valid str */ + if (!(convert_bool(data_str, &data_bool))) { + TRACE_ERROR_STRING("Failed to to convert bool value", data_str); + free(propcopy); + return EINVAL; + } + } + else { + /* It is an int */ + data_int = va_arg(args, int); + if (data_int) data_bool = 1; + else data_bool = 0; + } + + data = (void *)(&data_bool); + length = sizeof(unsigned char); + break; + + default: + TRACE_ERROR_STRING("Invalid or unknown type", propcopy); + free(propcopy); + return EINVAL; + } + + /* Insert or update */ + error = col_insert_property_with_ref(col, + NULL, + COL_DSP_END, + NULL, + 0, + COL_INSERT_DUPOVER, + propcopy, + type, + data, + length, + NULL); + if (error) { + TRACE_ERROR_STRING("Error inserting property", property); + free(propcopy); + return error; + } + } + else { + /* Remove case */ + while (error != ENOENT) { + error = col_delete_property(col, + propcopy, + COL_TYPE_ANY, + COL_TRAVERSE_DEFAULT); + + if ((error) && (error != ENOENT)) { + TRACE_ERROR_STRING("Error deleting property", propcopy); + free(propcopy); + return error; + } + } + error = EOK; + } + free(propcopy); + } + else { + /* Errors related to key interpretation are handled here */ + TRACE_ERROR_STRING("Invalid arg", arg); + return EINVAL; + } + } /* end of arg processing loop */ + + TRACE_FLOW_STRING("process_arg_list", "Exit"); + return error; +} + +static int get_default_template(struct collection_item **template) +{ + int error = EOK; + + TRACE_FLOW_STRING("get_default_template", "Entry"); + + if (!default_template) { + TRACE_INFO_STRING("Default template does not exit", ""); + error = elapi_set_default_template(E_BASE_DEFV1); + if (error) { + TRACE_ERROR_NUMBER("Set default template returned error", error); + return error; + } + } + + *template = default_template; + TRACE_FLOW_NUMBER("get_default_template. Exit returning", error); + return error; +} + +/* Cleanup callback installed when global template is used */ +void clean_template(void) +{ + TRACE_FLOW_STRING("clean_template", "Entry"); + elapi_destroy_event_template(default_template); + TRACE_FLOW_STRING("clean_template", "Exit"); +} + +/*****************************************************************************/ + +/* Create event template */ +int elapi_create_event_template(struct collection_item **template, + unsigned base, ...) +{ + int error = EOK; + struct collection_item *tpl = NULL; + va_list args; + + TRACE_FLOW_STRING("elapi_create_event_template", "Entry"); + + if (template == NULL ) { + TRACE_ERROR_STRING("Template storage must be provided", ""); + return EINVAL; + } + + *template = NULL; + + /* Create collection */ + error = col_create_collection(&tpl, E_TEMPLATE_NAME, COL_CLASS_ELAPI_TEMPLATE); + if (error) { + TRACE_ERROR_NUMBER("Failed to create collection. Error", error); + return error; + } + + /* Add elements using base mask */ + error = add_base_elements(tpl, base); + if (error) { + TRACE_ERROR_NUMBER("Failed to add base elements. Error", error); + col_destroy_collection(tpl); + return error; + } + + /* Process varible arguments */ + va_start(args, base); + + /* Process variable argument list */ + error = process_arg_list(tpl, args); + + va_end(args); + + if (error) { + TRACE_ERROR_NUMBER("Failed to process argument list. Error", error); + col_destroy_collection(tpl); + return error; + } + + *template = tpl; + + TRACE_FLOW_STRING("elapi_create_event_template", "Exit"); + return error; +} + +/* Function to destroy event template */ +void elapi_destroy_event_template(struct collection_item *template) +{ + TRACE_FLOW_STRING("elapi_destroy_event_template", "Entry"); + + col_destroy_collection(template); + + TRACE_FLOW_STRING("elapi_destroy_event_template", "Exit"); +} + +/* Create event */ +int elapi_create_event(struct collection_item **event, + struct collection_item *template, + struct collection_item *collection, + int mode, ...) +{ + int error = EOK; + struct collection_item *evt = NULL; + va_list args; + + TRACE_FLOW_STRING("elapi_create_event", "Entry"); + + /* Check storage */ + if (event == NULL ) { + TRACE_ERROR_STRING("Event storage must be provided", ""); + return EINVAL; + } + + /* Check for template */ + if (template == NULL ) { + TRACE_ERROR_STRING("Template argument is missing", ""); + return EINVAL; + } + + *event = NULL; + + /* Create collection */ + error = col_create_collection(&evt, E_EVENT_NAME, COL_CLASS_ELAPI_EVENT); + if (error) { + TRACE_ERROR_NUMBER("Failed to create collection. Error", error); + return error; + } + + /* Add elements from the template */ + error = col_add_collection_to_collection(evt, NULL, NULL, + (struct collection_item *)template, + COL_ADD_MODE_FLAT); + if (error) { + TRACE_ERROR_NUMBER("Failed to add elements from the template. Error", error); + col_destroy_collection(evt); + return error; + } + + /* Add elements from the template */ + if (collection != NULL) { + error = col_add_collection_to_collection(evt, NULL, NULL, collection, mode); + if (error) { + TRACE_ERROR_NUMBER("Failed to add elements from external collection. Error", error); + col_destroy_collection(evt); + return error; + } + } + + /* Process varible arguments */ + va_start(args, mode); + + /* Process variable argument list */ + error = process_arg_list(evt, args); + + va_end(args); + + if (error) { + TRACE_ERROR_NUMBER("Failed to process argument list. Error", error); + col_destroy_collection(evt); + return error; + } + + *event = evt; + + TRACE_FLOW_STRING("elapi_create_event", "Exit"); + return error; +} + +/* Add/Updates/Removes the event attributes based on the and provided key value pairs */ +int elapi_modify_event(struct collection_item *event, + struct collection_item *collection, + int mode, ...) +{ + int error = EOK; + va_list args; + + TRACE_FLOW_STRING("elapi_modify_event", "Entry"); + + /* Check event */ + if (event == NULL ) { + TRACE_ERROR_STRING("Event must be provided", ""); + return EINVAL; + } + + /* Add elements from the template */ + if (collection != NULL) { + error = col_add_collection_to_collection(event, NULL, NULL, collection, mode); + if (error) { + TRACE_ERROR_NUMBER("Failed to add elements from external collection. Error", error); + col_destroy_collection(event); + return error; + } + } + + /* Process varible arguments */ + va_start(args, mode); + + /* Process variable argument list */ + error = process_arg_list(event, args); + + va_end(args); + + if (error) { + TRACE_ERROR_NUMBER("Failed to process argument list. Error", error); + return error; + } + + TRACE_FLOW_STRING("elapi_modify_event", "Exit"); + return error; +} + +/* Create a copy of the event */ +int elapi_copy_event(struct collection_item **new_event, + struct collection_item *source_event) +{ + int error = EOK; + + TRACE_FLOW_STRING("elapi_copy_event", "Entry"); + + error = col_copy_collection(new_event, + source_event, + NULL); + + TRACE_FLOW_NUMBER("elapi_copy_event. Exit Returning", error); + return error; +} + +/* Function to destroy event. */ +void elapi_destroy_event(struct collection_item *event) +{ + TRACE_FLOW_STRING("elapi_destroy_event", "Entry"); + + col_destroy_collection(event); + + TRACE_FLOW_STRING("elapi_destroy_event", "Exit"); +} + +/* Initializes default internal template */ +int elapi_set_default_template(unsigned base, ...) +{ + int error = EOK; + struct collection_item *tpl; + va_list args; + + TRACE_FLOW_STRING("elapi_set_default_template", "Entry"); + + /* Clean previous instance of the default template */ + elapi_destroy_event_template(default_template); + default_template = NULL; + + /* Create collection */ + error = col_create_collection(&tpl, E_TEMPLATE_NAME, COL_CLASS_ELAPI_TEMPLATE); + if (error) { + TRACE_ERROR_NUMBER("Failed to create collection. Error", error); + return error; + } + + /* Add elements using base mask */ + error = add_base_elements(tpl, base); + if (error) { + TRACE_ERROR_NUMBER("Failed to add base elements. Error", error); + col_destroy_collection(tpl); + return error; + } + + /* Process varible arguments */ + va_start(args, base); + + /* Process variable argument list */ + error = process_arg_list(tpl, args); + + va_end(args); + + if (error) { + TRACE_ERROR_NUMBER("Failed to process argument list. Error", error); + col_destroy_collection(tpl); + return error; + } + + /* Install a cleanup callback */ + if (atexit(clean_template)) { + TRACE_ERROR_NUMBER("Failed to install cleanup callback. Error", ENOSYS); + col_destroy_collection(tpl); + /* NOTE: Could not find a better error for this case */ + return ENOSYS; + } + + default_template = tpl; + + TRACE_FLOW_STRING("elapi_set_default_template", "Exit"); + return error; +} + + +/* This function will use internal default template */ +int elapi_create_simple_event(struct collection_item **event, ...) +{ + int error = EOK; + struct collection_item *evt = NULL; + va_list args; + struct collection_item *template; + + TRACE_FLOW_STRING("elapi_create_simple_event", "Entry"); + + /* Check storage */ + if (event == NULL ) { + TRACE_ERROR_STRING("Event storage must be provided", ""); + return EINVAL; + } + + *event = NULL; + + error = get_default_template(&template); + if (error) { + TRACE_ERROR_NUMBER("Failed to get default template. Error", error); + return error; + } + + /* Create collection */ + error = col_create_collection(&evt, E_EVENT_NAME, COL_CLASS_ELAPI_EVENT); + if (error) { + TRACE_ERROR_NUMBER("Failed to create collection. Error", error); + return error; + } + + /* Add elements from the template */ + error = col_add_collection_to_collection(evt, NULL, NULL, + template, + COL_ADD_MODE_FLAT); + + if (error) { + TRACE_ERROR_NUMBER("Failed to add elements from the template. Error", error); + col_destroy_collection(evt); + return error; + } + + /* Process varible arguments */ + va_start(args, event); + + /* Process variable argument list */ + error = process_arg_list(evt, args); + + va_end(args); + + if (error) { + TRACE_ERROR_NUMBER("Failed to process argument list. Error", error); + col_destroy_collection(evt); + return error; + } + + *event = evt; + + TRACE_FLOW_STRING("elapi_create_simple_event", "Exit"); + return error; +} |