summaryrefslogtreecommitdiffstats
path: root/elapi/elapi_event.c
diff options
context:
space:
mode:
authorDmitri Pal <dpal@redhat.com>2009-07-13 19:35:31 -0400
committerStephen Gallagher <sgallagh@redhat.com>2009-07-15 11:19:46 -0400
commit51b3a661529f8e3fd5ada94b95d4ba393e339dd8 (patch)
treee96497349d5740445adfe57648469146b5256c4c /elapi/elapi_event.c
parent18871cab92aef80bd4a856454a77f8808984dbce (diff)
downloadding-libs2-51b3a661529f8e3fd5ada94b95d4ba393e339dd8.tar.gz
ding-libs2-51b3a661529f8e3fd5ada94b95d4ba393e339dd8.tar.xz
ding-libs2-51b3a661529f8e3fd5ada94b95d4ba393e339dd8.zip
ELAPI First part of the interface
This is just a part of the interface, a beginning. Most likely some of the functions will be altered but it is a starting point. For example in future there will be a way to override some of the parts of the default template using the application configuration file. Removed obfuscation of the data types based on discussion with Simo.
Diffstat (limited to 'elapi/elapi_event.c')
-rw-r--r--elapi/elapi_event.c1112
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;
+}