Implement filter bytecode support in lttng-session, and parse filter string
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 12 Jul 2012 17:01:14 +0000 (13:01 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 12 Jul 2012 17:23:10 +0000 (13:23 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
23 files changed:
configure.ac
include/lttng/lttng.h
src/bin/lttng-sessiond/Makefile.am
src/bin/lttng-sessiond/filter.c [new file with mode: 0644]
src/bin/lttng-sessiond/filter.h [new file with mode: 0644]
src/bin/lttng-sessiond/lttng-ust-abi.h
src/bin/lttng-sessiond/lttng-ust-ctl.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/trace-ust.c
src/bin/lttng-sessiond/trace-ust.h
src/bin/lttng-sessiond/ust-app.c
src/bin/lttng-sessiond/ust-app.h
src/bin/lttng/commands/enable_events.c
src/common/sessiond-comm/sessiond-comm.c
src/common/sessiond-comm/sessiond-comm.h
src/lib/lttng-ctl/Makefile.am
src/lib/lttng-ctl/filter-ast.h
src/lib/lttng-ctl/filter-bytecode.h
src/lib/lttng-ctl/filter-visitor-generate-bytecode.c
src/lib/lttng-ctl/lttng-ctl.c
src/lib/lttng-ctl/memstream.h [new file with mode: 0644]
tests/kernel/Makefile.am
tests/ust/Makefile.am

index cba96c1afd89d9930beafe3f76b934c60b635ad6..7934a5b27575ab6d7ed0f0cb1e74a8ba1128fa4b 100644 (file)
@@ -140,6 +140,20 @@ AC_CHECK_LIB([dl], [dlopen],
 AM_CONDITIONAL([LTTNG_TOOLS_BUILD_WITH_LIBDL], [test "x$have_libdl" = "xyes"])
 AM_CONDITIONAL([LTTNG_TOOLS_BUILD_WITH_LIBC_DL], [test "x$have_libc_dl" = "xyes"])
 
+# Check for fmemopen
+AC_CHECK_LIB([c], [fmemopen],
+[
+       AC_DEFINE_UNQUOTED([LTTNG_HAVE_FMEMOPEN], 1, [Has fmemopen support.])
+]
+)
+
+# Check for open_memstream
+AC_CHECK_LIB([c], [open_memstream],
+[
+       AC_DEFINE_UNQUOTED([LTTNG_HAVE_OPEN_MEMSTREAM], 1, [Has open_memstream support.])
+]
+)
+
 # Option to only build the consumer daemon and its libraries
 AC_ARG_WITH([consumerd-only],
        AS_HELP_STRING([--with-consumerd-only],[Only build the consumer daemon [default=no]]),
index 4741b68778f77522ad5d2cb975a4e80731bb01f5..598abe07777d4b8594219e980ed242795d74b31d 100644 (file)
@@ -548,6 +548,17 @@ extern int lttng_add_context(struct lttng_handle *handle,
 extern int lttng_enable_event(struct lttng_handle *handle,
                struct lttng_event *ev, const char *channel_name);
 
+/*
+ * Apply a filter expression to an event.
+ *
+ * If event_name is NULL, the filter is applied to all events of the channel.
+ * If channel_name is NULL, a lookup of the event's channel is done.
+ * If both are NULL, the filter is applied to all events of all channels.
+ */
+extern int lttng_set_event_filter(struct lttng_handle *handle,
+               const char *event_name,
+               const char *channel_name,
+               const char *filter_expression);
 /*
  * Create or enable a channel.
  * The channel name cannot be NULL.
index c9201f5dab1a13ba31b9fad1096165469702df6b..0cbf0c11a8f60f44f624d0c50b65ae12d7db9e2b 100644 (file)
@@ -19,7 +19,7 @@ lttng_sessiond_SOURCES = utils.c utils.h \
                        fd-limit.c fd-limit.h \
                        consumer.c consumer.h \
                        kernel-consumer.c kernel-consumer.h \
-                       consumer.h
+                       consumer.h filter.c filter.h
 
 if HAVE_LIBLTTNG_UST_CTL
 lttng_sessiond_SOURCES += trace-ust.c ust-app.c ust-consumer.c ust-consumer.h
diff --git a/src/bin/lttng-sessiond/filter.c b/src/bin/lttng-sessiond/filter.c
new file mode 100644 (file)
index 0000000..e012cb8
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <urcu/list.h>
+
+#include <common/error.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+
+#include "filter.h"
+#include "kernel.h"
+#include "ust-app.h"
+#include "trace-ust.h"
+
+/*
+ * Add UST context to event.
+ */
+static int add_ufilter_to_event(struct ltt_ust_session *usess, int domain,
+               struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent,
+               struct lttng_filter_bytecode *bytecode)
+{
+       int ret;
+
+       if (uevent->filter) {
+               ret = -EEXIST;
+               goto error;
+       }
+       /* Same layout. */
+       uevent->filter = (struct lttng_ust_filter_bytecode *) bytecode;
+
+       switch (domain) {
+       case LTTNG_DOMAIN_UST:
+               ret = ust_app_set_filter_event_glb(usess, uchan, uevent,
+                                               bytecode);
+               if (ret < 0) {
+                       goto error;
+               }
+               break;
+       default:
+               ret = -ENOSYS;
+               goto error;
+       }
+
+       DBG("Filter UST added to event %s",uevent->attr.name);
+
+       return 0;
+
+error:
+       free(bytecode);
+       return ret;
+}
+
+/*
+ * Add UST context to tracer.
+ */
+int filter_ust_set(struct ltt_ust_session *usess, int domain,
+               struct lttng_filter_bytecode *bytecode, char *event_name,
+               char *channel_name)
+{
+       int ret = LTTCOMM_OK, have_event = 0;
+       struct lttng_ht_iter iter;
+       struct lttng_ht *chan_ht;
+       struct ltt_ust_channel *uchan = NULL;
+       struct ltt_ust_event *uevent = NULL;
+
+       /*
+        * Define which channel's hashtable to use from the domain or quit if
+        * unknown domain.
+        */
+       switch (domain) {
+       case LTTNG_DOMAIN_UST:
+               chan_ht = usess->domain_global.channels;
+               break;
+#if 0
+       case LTTNG_DOMAIN_UST_EXEC_NAME:
+       case LTTNG_DOMAIN_UST_PID:
+       case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
+#endif
+       default:
+               ret = LTTCOMM_UND;
+               goto error;
+       }
+
+       /* Do we have an event name */
+       if (strlen(event_name) != 0) {
+               have_event = 1;
+       }
+
+       /* Get UST channel if defined */
+       if (strlen(channel_name) != 0) {
+               uchan = trace_ust_find_channel_by_name(chan_ht, channel_name);
+               if (uchan == NULL) {
+                       ret = LTTCOMM_UST_CHAN_NOT_FOUND;
+                       goto error;
+               }
+       }
+
+       /* If UST channel specified and event name, get UST event ref */
+       if (uchan && have_event) {
+               uevent = trace_ust_find_event_by_name(uchan->events, event_name);
+               if (uevent == NULL) {
+                       ret = LTTCOMM_UST_EVENT_NOT_FOUND;
+                       goto error;
+               }
+       }
+
+       /* At this point, we have 4 possibilities */
+
+       if (uchan && uevent) {                          /* Add filter to event in channel */
+               ret = add_ufilter_to_event(usess, domain, uchan, uevent,
+                                       bytecode);
+       } else if (uchan && !have_event) {      /* Add filter to channel */
+               ERR("Cannot add filter to channel");
+               ret = LTTCOMM_FATAL;    /* not supported. */
+               goto error;
+       } else if (!uchan && have_event) {      /* Add filter to event */
+               /* Add context to event without having the channel name */
+               cds_lfht_for_each_entry(chan_ht->ht, &iter.iter, uchan, node.node) {
+                       uevent = trace_ust_find_event_by_name(uchan->events, event_name);
+                       if (uevent != NULL) {
+                               ret = add_ufilter_to_event(usess, domain, uchan, uevent, bytecode);
+                               /*
+                                * LTTng UST does not allowed the same event to be registered
+                                * multiple time in different or the same channel. So, if we
+                                * found our event, we stop.
+                                */
+                               goto end;
+                       }
+               }
+               ret = LTTCOMM_UST_EVENT_NOT_FOUND;
+               goto error;
+       } else if (!uchan && !have_event) {     /* Add filter all events, all channels */
+               ERR("Cannot add filter to channel");
+               ret = LTTCOMM_FATAL;    /* not supported. */
+               goto error;
+       }
+
+end:
+       switch (ret) {
+       case -EEXIST:
+               ret = LTTCOMM_FILTER_EXIST;
+               break;
+       case -ENOMEM:
+               ret = LTTCOMM_FATAL;
+               break;
+       case -EINVAL:
+               ret = LTTCOMM_FILTER_INVAL;
+               break;
+       case -ENOSYS:
+               ret = LTTCOMM_UNKNOWN_DOMAIN;
+               break;
+       default:
+               ret = LTTCOMM_OK;
+               break;
+       }
+
+error:
+       return ret;
+}
diff --git a/src/bin/lttng-sessiond/filter.h b/src/bin/lttng-sessiond/filter.h
new file mode 100644 (file)
index 0000000..d706824
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _LTT_FILTER_H
+#define _LTT_FILTER_H
+
+#include <lttng/lttng.h>
+
+#include "trace-kernel.h"
+#include "trace-ust.h"
+#include "ust-ctl.h"
+
+struct lttng_filter_bytecode;
+
+int filter_ust_set(struct ltt_ust_session *usess, int domain,
+               struct lttng_filter_bytecode *bytecode, char *event_name,
+               char *channel_name);
+
+#endif /* _LTT_FILTER_H */
index dc6ad7ab68dc11a6228f57908f5250928f8516b2..d8b10c257039effd035a9c7edc04fd4fba356d6f 100644 (file)
@@ -168,6 +168,13 @@ struct lttng_ust_calibrate {
        } u;
 };
 
+#define FILTER_BYTECODE_MAX_LEN                65535
+struct lttng_ust_filter_bytecode {
+       uint16_t len;
+       uint16_t reloc_offset;
+       char data[0];
+};
+
 #define _UST_CMD(minor)                                (minor)
 #define _UST_CMDR(minor, type)                 (minor)
 #define _UST_CMDW(minor, type)                 (minor)
index c3479c97b818bfe8cace2a592d973c075d53cf7a..9baf443f3fd443353c99c054c0f00bd756c86395 100644 (file)
@@ -37,6 +37,8 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev,
 int ustctl_add_context(int sock, struct lttng_ust_context *ctx,
                struct lttng_ust_object_data *obj_data,
                struct lttng_ust_object_data **context_data);
+int ustctl_set_filter(int sock, struct lttng_ust_filter_bytecode *bytecode,
+               struct lttng_ust_object_data *obj_data);
 
 int ustctl_enable(int sock, struct lttng_ust_object_data *object);
 int ustctl_disable(int sock, struct lttng_ust_object_data *object);
index a15721d76ae529b0fa45bfcfebec8b481931bdee..e2ca01eb54fe6541323f971095c1d329f28cf747 100644 (file)
@@ -58,6 +58,7 @@
 #include "ust-consumer.h"
 #include "utils.h"
 #include "fd-limit.h"
+#include "filter.h"
 
 #define CONSUMERD_FILE "lttng-consumerd"
 
@@ -2731,6 +2732,46 @@ error:
        return ret;
 }
 
+/*
+ * Command LTTNG_SET_FILTER processed by the client thread.
+ */
+static int cmd_set_filter(struct ltt_session *session, int domain,
+               char *channel_name, char *event_name,
+               struct lttng_filter_bytecode *bytecode)
+{
+       int ret;
+
+       switch (domain) {
+       case LTTNG_DOMAIN_KERNEL:
+               ret = LTTCOMM_FATAL;
+               break;
+       case LTTNG_DOMAIN_UST:
+       {
+               struct ltt_ust_session *usess = session->ust_session;
+
+               ret = filter_ust_set(usess, domain, bytecode, event_name, channel_name);
+               if (ret != LTTCOMM_OK) {
+                       goto error;
+               }
+               break;
+       }
+#if 0
+       case LTTNG_DOMAIN_UST_EXEC_NAME:
+       case LTTNG_DOMAIN_UST_PID:
+       case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
+#endif
+       default:
+               ret = LTTCOMM_UND;
+               goto error;
+       }
+
+       ret = LTTCOMM_OK;
+
+error:
+       return ret;
+
+}
+
 /*
  * Command LTTNG_ENABLE_EVENT processed by the client thread.
  */
@@ -3928,8 +3969,11 @@ error:
  * is set and ready for transmission before returning.
  *
  * Return any error encountered or 0 for success.
+ *
+ * "sock" is only used for special-case var. len data.
  */
-static int process_client_msg(struct command_ctx *cmd_ctx)
+static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
+               int *sock_error)
 {
        int ret = LTTCOMM_OK;
        int need_tracing_session = 1;
@@ -3937,6 +3981,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx)
 
        DBG("Processing client command %d", cmd_ctx->lsm->cmd_type);
 
+       *sock_error = 0;
+
        switch (cmd_ctx->lsm->cmd_type) {
        case LTTNG_CREATE_SESSION:
        case LTTNG_CREATE_SESSION_URI:
@@ -4447,6 +4493,43 @@ skip_domain:
                                cmd_ctx->lsm->u.reg.path);
                break;
        }
+       case LTTNG_SET_FILTER:
+       {
+               struct lttng_filter_bytecode *bytecode;
+
+               if (cmd_ctx->lsm->u.filter.bytecode_len > 65336) {
+                       ret = LTTCOMM_FILTER_INVAL;
+                       goto error;
+               }
+               bytecode = zmalloc(cmd_ctx->lsm->u.filter.bytecode_len);
+               if (!bytecode) {
+                       ret = LTTCOMM_FILTER_NOMEM;
+                       goto error;
+               }
+               /* Receive var. len. data */
+               DBG("Receiving var len data from client ...");
+               ret = lttcomm_recv_unix_sock(sock, bytecode,
+                               cmd_ctx->lsm->u.filter.bytecode_len);
+               if (ret <= 0) {
+                       DBG("Nothing recv() from client var len data... continuing");
+                       *sock_error = 1;
+                       ret = LTTCOMM_FILTER_INVAL;
+                       goto error;
+               }
+
+               if (bytecode->len + sizeof(*bytecode)
+                               != cmd_ctx->lsm->u.filter.bytecode_len) {
+                       free(bytecode);
+                       ret = LTTCOMM_FILTER_INVAL;
+                       goto error;
+               }
+
+               ret = cmd_set_filter(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+                               cmd_ctx->lsm->u.filter.channel_name,
+                               cmd_ctx->lsm->u.filter.event_name,
+                               bytecode);
+               break;
+       }
        default:
                ret = LTTCOMM_UND;
                break;
@@ -4479,6 +4562,7 @@ init_setup_error:
 static void *thread_manage_clients(void *data)
 {
        int sock = -1, ret, i, pollfd;
+       int sock_error;
        uint32_t revents, nb_fd;
        struct command_ctx *cmd_ctx = NULL;
        struct lttng_poll_event events;
@@ -4611,13 +4695,22 @@ static void *thread_manage_clients(void *data)
                 * informations for the client. The command context struct contains
                 * everything this function may needs.
                 */
-               ret = process_client_msg(cmd_ctx);
+               ret = process_client_msg(cmd_ctx, sock, &sock_error);
                rcu_thread_offline();
                if (ret < 0) {
+                       if (sock_error) {
+                               ret = close(sock);
+                               if (ret) {
+                                       PERROR("close");
+                               }
+                               sock = -1;
+                       }
                        /*
                         * TODO: Inform client somehow of the fatal error. At
                         * this point, ret < 0 means that a zmalloc failed
-                        * (ENOMEM). Error detected but still accept command.
+                        * (ENOMEM). Error detected but still accept
+                        * command, unless a socket error has been
+                        * detected.
                         */
                        clean_command_ctx(&cmd_ctx);
                        continue;
index cd1660d593dbf16a96c662a3bf0a7a143653cb9a..4001ec87bdd8359f6224a1915e84c62f9c22486a 100644 (file)
@@ -410,7 +410,7 @@ void trace_ust_destroy_event(struct ltt_ust_event *event)
 {
        DBG2("Trace destroy UST event %s", event->attr.name);
        destroy_contexts(event->ctx);
-
+       free(event->filter);
        free(event);
 }
 
index f8bcb3356fa7a3bc8010800737b83626157a62f0..845bcd6c91965b309114a04f539098aad3f4f16f 100644 (file)
@@ -46,6 +46,7 @@ struct ltt_ust_event {
        struct lttng_ust_event attr;
        struct lttng_ht *ctx;
        struct lttng_ht_node_str node;
+       struct lttng_ust_filter_bytecode *filter;
 };
 
 /* UST stream */
index c8c653134f7528e2cea26f0d333fc655881fe9e0..6fb328eb9ca0cfd991328d227445d1aa6fbdadca 100644 (file)
@@ -32,6 +32,7 @@
 #include "ust-consumer.h"
 #include "ust-ctl.h"
 #include "fd-limit.h"
+#include "../../common/sessiond-comm/sessiond-comm.h"
 
 /*
  * Delete ust context safely. RCU read lock must be held before calling
@@ -65,6 +66,7 @@ void delete_ust_app_event(int sock, struct ust_app_event *ua_event)
                assert(!ret);
                delete_ust_app_ctx(sock, ua_ctx);
        }
+       free(ua_event->filter);
        lttng_ht_destroy(ua_event->ctx);
 
        if (ua_event->obj != NULL) {
@@ -430,6 +432,31 @@ error:
        return ret;
 }
 
+/*
+ * Set the filter on the tracer.
+ */
+static
+int set_ust_event_filter(struct ust_app_event *ua_event,
+               struct ust_app *app)
+{
+       int ret;
+
+       if (!ua_event->filter) {
+               return 0;
+       }
+
+       ret = ustctl_set_filter(app->sock, ua_event->filter,
+                       ua_event->obj);
+       if (ret < 0) {
+               goto error;
+       }
+
+       DBG2("UST filter set successfully for event %s", ua_event->name);
+
+error:
+       return ret;
+}
+
 /*
  * Disable the specified event on to UST tracer for the UST session.
  */
@@ -705,6 +732,16 @@ static void shadow_copy_event(struct ust_app_event *ua_event,
        /* Copy event attributes */
        memcpy(&ua_event->attr, &uevent->attr, sizeof(ua_event->attr));
 
+       /* Copy filter bytecode */
+       if (uevent->filter) {
+               ua_event->filter = zmalloc(sizeof(*ua_event->filter) +
+                       uevent->filter->len);
+               if (!ua_event->filter) {
+                       return;
+               }
+               memcpy(ua_event->filter, uevent->filter,
+                       sizeof(*ua_event->filter) + uevent->filter->len);
+       }
        cds_lfht_for_each_entry(uevent->ctx->ht, &iter.iter, uctx, node.node) {
                ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
                if (ua_ctx == NULL) {
@@ -997,6 +1034,35 @@ error:
        return ret;
 }
 
+/*
+ * Set UST filter for the event on the tracer.
+ */
+static
+int set_ust_app_event_filter(struct ust_app_session *ua_sess,
+               struct ust_app_event *ua_event,
+               struct lttng_filter_bytecode *bytecode,
+               struct ust_app *app)
+{
+       int ret = 0;
+
+       DBG2("UST app adding context to event %s", ua_event->name);
+
+       /* Copy filter bytecode */
+       ua_event->filter = zmalloc(sizeof(*ua_event->filter) + bytecode->len);
+       if (!ua_event->filter) {
+               return -ENOMEM;
+       }
+       memcpy(ua_event->filter, bytecode,
+               sizeof(*ua_event->filter) + bytecode->len);
+       ret = set_ust_event_filter(ua_event, app);
+       if (ret < 0) {
+               goto error;
+       }
+
+error:
+       return ret;
+}
+
 /*
  * Enable on the tracer side a ust app event for the session and channel.
  */
@@ -2419,6 +2485,11 @@ void ust_app_global_update(struct ltt_ust_session *usess, int sock)
                                        continue;
                                }
                        }
+                       ret = set_ust_event_filter(ua_event, app);
+                       if (ret < 0) {
+                               /* FIXME: Should we quit here or continue... */
+                               continue;
+                       }
                }
        }
 
@@ -2540,6 +2611,63 @@ int ust_app_add_ctx_event_glb(struct ltt_ust_session *usess,
        return ret;
 }
 
+/*
+ * Add context to a specific event in a channel for global UST domain.
+ */
+int ust_app_set_filter_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent,
+               struct lttng_filter_bytecode *bytecode)
+{
+       int ret = 0;
+       struct lttng_ht_node_str *ua_chan_node, *ua_event_node;
+       struct lttng_ht_iter iter, uiter;
+       struct ust_app_session *ua_sess;
+       struct ust_app_event *ua_event;
+       struct ust_app_channel *ua_chan = NULL;
+       struct ust_app *app;
+
+       rcu_read_lock();
+
+       cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+               if (!app->compatible) {
+                       /*
+                        * TODO: In time, we should notice the caller of this error by
+                        * telling him that this is a version error.
+                        */
+                       continue;
+               }
+               ua_sess = lookup_session_by_app(usess, app);
+               if (ua_sess == NULL) {
+                       continue;
+               }
+
+               /* Lookup channel in the ust app session */
+               lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
+               ua_chan_node = lttng_ht_iter_get_node_str(&uiter);
+               if (ua_chan_node == NULL) {
+                       continue;
+               }
+               ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel,
+                               node);
+
+               lttng_ht_lookup(ua_chan->events, (void *)uevent->attr.name, &uiter);
+               ua_event_node = lttng_ht_iter_get_node_str(&uiter);
+               if (ua_event_node == NULL) {
+                       continue;
+               }
+               ua_event = caa_container_of(ua_event_node, struct ust_app_event,
+                               node);
+
+               ret = set_ust_app_event_filter(ua_sess, ua_event, bytecode, app);
+               if (ret < 0) {
+                       continue;
+               }
+       }
+
+       rcu_read_unlock();
+       return ret;
+}
+
 /*
  * Enable event for a channel from a UST session for a specific PID.
  */
index 29eaea7ec4141706a7ebc75ddfa770bc773614b3..77205692ff989f157a4799529fb254ad21a381a1 100644 (file)
@@ -28,6 +28,9 @@
 
 #define UST_APP_EVENT_LIST_SIZE 32
 
+struct lttng_filter_bytecode;
+struct lttng_ust_filter_bytecode;
+
 extern int ust_consumerd64_fd, ust_consumerd32_fd;
 
 /*
@@ -71,6 +74,7 @@ struct ust_app_event {
        char name[LTTNG_UST_SYM_NAME_LEN];
        struct lttng_ht *ctx;
        struct lttng_ht_node_str node;
+       struct lttng_ust_filter_bytecode *filter;
 };
 
 struct ust_app_channel {
@@ -168,6 +172,9 @@ int ust_app_add_ctx_event_glb(struct ltt_ust_session *usess,
                struct ltt_ust_context *uctx);
 int ust_app_add_ctx_channel_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_context *uctx);
+int ust_app_set_filter_event_glb(struct ltt_ust_session *usess,
+                struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent,
+               struct lttng_filter_bytecode *bytecode);
 void ust_app_global_update(struct ltt_ust_session *usess, int sock);
 
 void ust_app_clean_list(void);
index 5dda8bf8c64ceaa3895c48b7dbbe3dd323d0e876..3f304a0902ad398bfddacc76ba97ca6595836685 100644 (file)
@@ -41,6 +41,7 @@ static char *opt_probe;
 static char *opt_function;
 static char *opt_function_entry_symbol;
 static char *opt_channel_name;
+static char *opt_filter;
 #if 0
 /* Not implemented yet */
 static char *opt_cmd_name;
@@ -58,6 +59,7 @@ enum {
        OPT_LOGLEVEL,
        OPT_LOGLEVEL_ONLY,
        OPT_LIST_OPTIONS,
+       OPT_FILTER,
 };
 
 static struct lttng_handle *handle;
@@ -90,6 +92,7 @@ static struct poptOption long_options[] = {
        {"loglevel",       0,     POPT_ARG_STRING, 0, OPT_LOGLEVEL, 0, 0},
        {"loglevel-only",  0,     POPT_ARG_STRING, 0, OPT_LOGLEVEL_ONLY, 0, 0},
        {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"filter",         'f', POPT_ARG_STRING, &opt_filter, OPT_FILTER, 0, 0},
        {0, 0, 0, 0, 0, 0, 0}
 };
 
@@ -162,6 +165,9 @@ static void usage(FILE *ofp)
        fprintf(ofp, "                               TRACE_DEBUG_LINE     = 13\n");
        fprintf(ofp, "                               TRACE_DEBUG          = 14\n");
        fprintf(ofp, "                               (shortcuts such as \"system\" are allowed)\n");
+       fprintf(ofp, "    --filter \'expression\'\n");
+       fprintf(ofp, "                           Filter expression on event fields,\n");
+       fprintf(ofp, "                           event recording depends on evaluation.\n");
        fprintf(ofp, "\n");
 }
 
@@ -294,6 +300,14 @@ static int enable_events(char *session_name)
        memset(&ev, 0, sizeof(ev));
        memset(&dom, 0, sizeof(dom));
 
+       if (opt_kernel) {
+               if (opt_filter) {
+                       ERR("Filter not implement for kernel tracing yet");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
        /* Create lttng domain */
        if (opt_kernel) {
                dom.type = LTTNG_DOMAIN_KERNEL;
@@ -358,6 +372,15 @@ static int enable_events(char *session_name)
                        }
                        goto end;
                }
+               if (opt_filter) {
+                       ret = lttng_set_event_filter(handle, ev.name, channel_name,
+                                               opt_filter);
+                       if (ret < 0) {
+                               ERR("Error setting filter");
+                               ret = -1;
+                               goto error;
+                       }
+               }
 
                switch (opt_event_type) {
                case LTTNG_EVENT_TRACEPOINT:
@@ -519,6 +542,15 @@ static int enable_events(char *session_name)
                        MSG("%s event %s created in channel %s",
                                        opt_kernel ? "kernel": "UST", event_name, channel_name);
                }
+               if (opt_filter) {
+                       ret = lttng_set_event_filter(handle, ev.name,
+                               channel_name, opt_filter);
+                       if (ret < 0) {
+                               ERR("Error setting filter");
+                               ret = -1;
+                               goto error;
+                       }
+               }
 
                /* Next event */
                event_name = strtok(NULL, ",");
@@ -586,6 +618,8 @@ int cmd_enable_events(int argc, const char **argv)
                case OPT_LIST_OPTIONS:
                        list_cmd_options(stdout, long_options);
                        goto end;
+               case OPT_FILTER:
+                       break;
                default:
                        usage(stderr);
                        ret = CMD_UNDEFINED;
index 6cbd014b8c3db26be2ee7cfeb7ba421d489e2837..432cf4cfff746e014cd66b1af465338076b4a0c2 100644 (file)
@@ -143,6 +143,9 @@ static const char *lttcomm_readable_code[] = {
        [ LTTCOMM_ERR_INDEX(LTTCOMM_ENABLE_CONSUMER_FAIL) ] = "Enabling consumer failed",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_RELAYD_SESSION_FAIL) ] = "Unable to create session on lttng-relayd",
        [ LTTCOMM_ERR_INDEX(LTTCOMM_RELAYD_VERSION_FAIL) ] = "Relay daemon not compatible",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_FILTER_INVAL) ] = "Invalid filter bytecode",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_FILTER_NOMEM) ] = "Not enough memory for filter bytecode",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_FILTER_EXIST) ] = "Filter already exist",
 };
 
 /*
index 580beec32b74953a4f08099220837183edb40b1e..f48ba221849f8a3683fb8273cc23a2c156fd75b3 100644 (file)
@@ -72,6 +72,7 @@ enum lttcomm_sessiond_command {
        LTTNG_START_TRACE,
        LTTNG_STOP_TRACE,
        LTTNG_LIST_TRACEPOINT_FIELDS,
+
        /* Consumer */
        LTTNG_DISABLE_CONSUMER,
        LTTNG_ENABLE_CONSUMER,
@@ -83,6 +84,9 @@ enum lttcomm_sessiond_command {
        RELAYD_UPDATE_SYNC_INFO,
        RELAYD_VERSION,
        RELAYD_SEND_METADATA,
+
+       /* Other tracer commands */
+       LTTNG_SET_FILTER,
 };
 
 /*
@@ -186,6 +190,9 @@ enum lttcomm_return_code {
        LTTCOMM_ENABLE_CONSUMER_FAIL,   /* Enabling consumer failed */
        LTTCOMM_RELAYD_SESSION_FAIL,    /* lttng-relayd create session failed */
        LTTCOMM_RELAYD_VERSION_FAIL,    /* lttng-relayd not compatible */
+       LTTCOMM_FILTER_INVAL,           /* Invalid filter bytecode */
+       LTTCOMM_FILTER_NOMEM,           /* Lack of memory for filter bytecode */
+       LTTCOMM_FILTER_EXIST,           /* Filter already exist */
 
        /* MUST be last element */
        LTTCOMM_NR,                                             /* Last element */
@@ -280,9 +287,28 @@ struct lttcomm_session_msg {
                        struct lttng_uri ctrl_uri;
                        struct lttng_uri data_uri;
                } create_uri;
+               struct {
+                       char channel_name[NAME_MAX];
+                       char event_name[NAME_MAX];
+                       /* Length of following bytecode */
+                       uint32_t bytecode_len;
+               } filter;
        } u;
 };
 
+#define LTTNG_FILTER_MAX_LEN   65336
+
+/*
+ * Filter bytecode data. The reloc table is located at the end of the
+ * bytecode. It is made of tuples: (uint16_t, var. len. string). It
+ * starts at reloc_table_offset.
+ */
+struct lttng_filter_bytecode {
+       uint16_t len;   /* len of data */
+       uint16_t reloc_table_offset;
+       char data[0];
+};
+
 /*
  * Data structure for the response from sessiond to the lttng client.
  */
index 4f61d5b01e1d2f5dc835faa659cfc7ae83fe9317..bb5561e792cb76dea2d3622a1539c311b61e37dc 100644 (file)
@@ -15,7 +15,8 @@ liblttng_ctl_la_SOURCES = lttng-ctl.c \
        align.h \
        filter-ast.h \
        filter-bytecode.h \
-       filter-ir.h
+       filter-ir.h \
+       memstream.h
 
 filter_grammar_test_SOURCES = filter-grammar-test.c
 filter_grammar_test_LDADD = liblttng-ctl.la
index 816562e230ce30bdd7ed498da172963b073e9535..97a3ae410001a91f62c98d4dbb1f54ea331a96cf 100644 (file)
@@ -152,15 +152,14 @@ struct filter_ast {
 const char *node_type(struct filter_node *node);
 
 struct ir_op;
-struct filter_bytecode;
 
 struct filter_parser_ctx {
        yyscan_t scanner;
        struct filter_ast *ast;
        struct cds_list_head allocated_strings;
        struct ir_op *ir_root;
-       struct filter_bytecode_alloc *bytecode;
-       struct filter_bytecode_alloc *bytecode_reloc;
+       struct lttng_filter_bytecode_alloc *bytecode;
+       struct lttng_filter_bytecode_alloc *bytecode_reloc;
 };
 
 struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input);
index fc2d6c8d4c5cf78f8e9965673040b112c6d5bbc8..af0733076a473201edd6ca94d032342ffe71b9ad 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include "filter-ast.h"
+#include "../../common/sessiond-comm/sessiond-comm.h"
 
 /*
  * offsets are absolute from start of bytecode.
@@ -123,24 +124,13 @@ struct return_op {
        filter_opcode_t op;
 } __attribute__((packed));
 
-/*
- * The reloc table is located at the end of the bytecode. It is made of
- * tuples: (uint16_t, var. len. string). It starts at
- * reloc_table_offset.
- */
-struct filter_bytecode {
-       uint16_t len;
-       uint16_t reloc_table_offset;
-       char data[0];
-};
-
-struct filter_bytecode_alloc {
+struct lttng_filter_bytecode_alloc {
        uint16_t alloc_len;
-       struct filter_bytecode b;
+       struct lttng_filter_bytecode b;
 };
 
 static inline
-unsigned int bytecode_get_len(struct filter_bytecode *bytecode)
+unsigned int bytecode_get_len(struct lttng_filter_bytecode *bytecode)
 {
        return bytecode->len;
 }
index e940e2c81ab6f85ea8313018d58f5fc7d51f8e6e..25128b6a2fc6b9f2bd1826f66efbe8909d8f4a23 100644 (file)
@@ -39,9 +39,9 @@ int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
                struct ir_op *node);
 
 static
-int bytecode_init(struct filter_bytecode_alloc **fb)
+int bytecode_init(struct lttng_filter_bytecode_alloc **fb)
 {
-       *fb = calloc(sizeof(struct filter_bytecode_alloc) + INIT_ALLOC_SIZE, 1);
+       *fb = calloc(sizeof(struct lttng_filter_bytecode_alloc) + INIT_ALLOC_SIZE, 1);
        if (!*fb) {
                return -ENOMEM;
        } else {
@@ -51,7 +51,7 @@ int bytecode_init(struct filter_bytecode_alloc **fb)
 }
 
 static
-int32_t bytecode_reserve(struct filter_bytecode_alloc **fb, uint32_t align, uint32_t len)
+int32_t bytecode_reserve(struct lttng_filter_bytecode_alloc **fb, uint32_t align, uint32_t len)
 {
        int32_t ret;
        uint32_t padding = offset_align((*fb)->b.len, align);
@@ -64,7 +64,7 @@ int32_t bytecode_reserve(struct filter_bytecode_alloc **fb, uint32_t align, uint
 
                if (new_len > 0xFFFF)
                        return -EINVAL;
-               *fb = realloc(*fb, sizeof(struct filter_bytecode_alloc) + new_len);
+               *fb = realloc(*fb, sizeof(struct lttng_filter_bytecode_alloc) + new_len);
                if (!*fb)
                        return -ENOMEM;
                memset(&(*fb)->b.data[old_len], 0, new_len - old_len);
@@ -77,7 +77,7 @@ int32_t bytecode_reserve(struct filter_bytecode_alloc **fb, uint32_t align, uint
 }
 
 static
-int bytecode_push(struct filter_bytecode_alloc **fb, const void *data,
+int bytecode_push(struct lttng_filter_bytecode_alloc **fb, const void *data,
                uint32_t align, uint32_t len)
 {
        int32_t offset;
@@ -90,7 +90,7 @@ int bytecode_push(struct filter_bytecode_alloc **fb, const void *data,
 }
 
 static
-int bytecode_push_logical(struct filter_bytecode_alloc **fb,
+int bytecode_push_logical(struct lttng_filter_bytecode_alloc **fb,
                struct logical_op *data,
                uint32_t align, uint32_t len,
                uint16_t *skip_offset)
@@ -108,7 +108,7 @@ int bytecode_push_logical(struct filter_bytecode_alloc **fb,
 }
 
 static
-int bytecode_patch(struct filter_bytecode_alloc **fb,
+int bytecode_patch(struct lttng_filter_bytecode_alloc **fb,
                const void *data,
                uint16_t offset,
                uint32_t len)
index a05a8049ec5dd7186fe83fa01ce83478a41f392f..780b44dd7cdebba0ed70c69a4459abc42df38658 100644 (file)
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <lttng/lttng.h>
 
+#include "filter-parser.h"
+#include "filter-ast.h"
+#include "filter-bytecode.h"
+#include "memstream.h"
+
+#ifdef DEBUG
+const int print_xml = 1;
+#define dbg_printf(fmt, args...)       \
+       printf("[debug liblttng-ctl] " fmt, ## args)
+#else
+const int print_xml = 0;
+#define dbg_printf(fmt, args...)                               \
+do {                                                           \
+       /* do nothing but check printf format */                \
+       if (0)                                                  \
+               printf("[debug liblttnctl] " fmt, ## args);     \
+} while (0)
+#endif
+
+
 /* Socket to session daemon for communication */
 static int sessiond_socket;
 static char sessiond_sock_path[PATH_MAX];
@@ -114,6 +134,31 @@ end:
        return ret;
 }
 
+/*
+ * Send var len data to the session daemon.
+ *
+ * On success, returns the number of bytes sent (>=0)
+ * On error, returns -1
+ */
+static int send_session_varlen(void *data, size_t len)
+{
+       int ret;
+
+       if (!connected) {
+               ret = -ENOTCONN;
+               goto end;
+       }
+       if (!data || !len) {
+               ret = 0;
+               goto end;
+       }
+
+       ret = lttcomm_send_unix_sock(sessiond_socket, data, len);
+
+end:
+       return ret;
+}
+
 /*
  * Receive data from the sessiond socket.
  *
@@ -311,10 +356,14 @@ static int disconnect_sessiond(void)
 
 /*
  * Ask the session daemon a specific command and put the data into buf.
+ * Takes extra var. len. data as input to send to the session daemon.
  *
  * Return size of data (only payload, not header) or a negative error code.
  */
-static int ask_sessiond(struct lttcomm_session_msg *lsm, void **buf)
+static int ask_sessiond_varlen(struct lttcomm_session_msg *lsm,
+               void *vardata,
+               size_t varlen,
+               void **buf)
 {
        int ret;
        size_t size;
@@ -331,6 +380,11 @@ static int ask_sessiond(struct lttcomm_session_msg *lsm, void **buf)
        if (ret < 0) {
                goto end;
        }
+       /* Send var len data */
+       ret = send_session_varlen(vardata, varlen);
+       if (ret < 0) {
+               goto end;
+       }
 
        /* Get header from data transmission */
        ret = recv_data_sessiond(&llm, sizeof(llm));
@@ -381,6 +435,16 @@ end:
        return ret;
 }
 
+/*
+ * Ask the session daemon a specific command and put the data into buf.
+ *
+ * Return size of data (only payload, not header) or a negative error code.
+ */
+static int ask_sessiond(struct lttcomm_session_msg *lsm, void **buf)
+{
+       return ask_sessiond_varlen(lsm, NULL, 0, buf);
+}
+
 /*
  * Create lttng handle and return pointer.
  * The returned pointer will be NULL in case of malloc() error.
@@ -555,6 +619,139 @@ int lttng_enable_event(struct lttng_handle *handle,
        return ask_sessiond(&lsm, NULL);
 }
 
+/*
+ * set filter for an event
+ * Return negative error value on error.
+ * Return size of returned session payload data if OK.
+ */
+
+int lttng_set_event_filter(struct lttng_handle *handle,
+               const char *event_name, const char *channel_name,
+               const char *filter_expression)
+{
+       struct lttcomm_session_msg lsm;
+       struct filter_parser_ctx *ctx;
+       FILE *fmem;
+       int ret = 0;
+
+       /* Safety check. */
+       if (handle == NULL) {
+               return -1;
+       }
+
+       if (!filter_expression) {
+               return 0;
+       }
+
+       /*
+        * casting const to non-const, as the underlying function will
+        * use it in read-only mode.
+        */
+       fmem = lttng_fmemopen((void *) filter_expression,
+                       strlen(filter_expression), "r");
+       if (!fmem) {
+               fprintf(stderr, "Error opening memory as stream\n");
+               return -ENOMEM;
+       }
+       ctx = filter_parser_ctx_alloc(fmem);
+       if (!ctx) {
+               fprintf(stderr, "Error allocating parser\n");
+               ret = -ENOMEM;
+               goto alloc_error;
+       }
+       ret = filter_parser_ctx_append_ast(ctx);
+       if (ret) {
+               fprintf(stderr, "Parse error\n");
+               ret = -EINVAL;
+               goto parse_error;
+       }
+       ret = filter_visitor_set_parent(ctx);
+       if (ret) {
+               fprintf(stderr, "Set parent error\n");
+               ret = -EINVAL;
+               goto parse_error;
+       }
+       if (print_xml) {
+               ret = filter_visitor_print_xml(ctx, stdout, 0);
+               if (ret) {
+                       fflush(stdout);
+                       fprintf(stderr, "XML print error\n");
+                       ret = -EINVAL;
+                       goto parse_error;
+               }
+       }
+
+       dbg_printf("Generating IR... ");
+       fflush(stdout);
+       ret = filter_visitor_ir_generate(ctx);
+       if (ret) {
+               fprintf(stderr, "Generate IR error\n");
+               ret = -EINVAL;
+               goto parse_error;
+       }
+       dbg_printf("done\n");
+
+       dbg_printf("Validating IR... ");
+       fflush(stdout);
+       ret = filter_visitor_ir_check_binary_op_nesting(ctx);
+       if (ret) {
+               ret = -EINVAL;
+               goto parse_error;
+       }
+       dbg_printf("done\n");
+
+       dbg_printf("Generating bytecode... ");
+       fflush(stdout);
+       ret = filter_visitor_bytecode_generate(ctx);
+       if (ret) {
+               fprintf(stderr, "Generate bytecode error\n");
+               ret = -EINVAL;
+               goto parse_error;
+       }
+       dbg_printf("done\n");
+       dbg_printf("Size of bytecode generated: %u bytes.\n",
+               bytecode_get_len(&ctx->bytecode->b));
+
+       memset(&lsm, 0, sizeof(lsm));
+
+       lsm.cmd_type = LTTNG_SET_FILTER;
+
+       /* Copy channel name */
+       copy_string(lsm.u.filter.channel_name, channel_name,
+                       sizeof(lsm.u.filter.channel_name));
+       /* Copy event name */
+       copy_string(lsm.u.filter.event_name, event_name,
+                       sizeof(lsm.u.filter.event_name));
+       lsm.u.filter.bytecode_len = sizeof(ctx->bytecode->b)
+                       + bytecode_get_len(&ctx->bytecode->b);
+
+       copy_lttng_domain(&lsm.domain, &handle->domain);
+
+       copy_string(lsm.session.name, handle->session_name,
+                       sizeof(lsm.session.name));
+
+       ret = ask_sessiond_varlen(&lsm, &ctx->bytecode->b,
+                               lsm.u.filter.bytecode_len, NULL);
+
+       filter_bytecode_free(ctx);
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+       if (fclose(fmem) != 0) {
+               perror("fclose");
+       }
+       return ret;
+
+parse_error:
+       filter_bytecode_free(ctx);
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+alloc_error:
+       if (fclose(fmem) != 0) {
+               perror("fclose");
+       }
+       return ret;
+}
+
 /*
  *  Disable event(s) of a channel and domain.
  *  If no event name is specified, all events are disabled.
diff --git a/src/lib/lttng-ctl/memstream.h b/src/lib/lttng-ctl/memstream.h
new file mode 100644 (file)
index 0000000..2cbb035
--- /dev/null
@@ -0,0 +1,228 @@
+#ifndef _LTTNG_CTL_MEMSTREAM_H
+#define _LTTNG_CTL_MEMSTREAM_H
+
+/*
+ * src/lib/lttng-ctl/memstream.h
+ *
+ * Copyright 2012 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * memstream compatibility layer.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define _GNU_SOURCE
+#include <config.h>
+
+#ifdef LTTNG_HAVE_FMEMOPEN
+#include <stdio.h>
+
+static inline
+FILE *lttng_fmemopen(void *buf, size_t size, const char *mode)
+{
+       return fmemopen(buf, size, mode);
+}
+
+#else /* LTTNG_HAVE_FMEMOPEN */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * Fallback for systems which don't have fmemopen. Copy buffer to a
+ * temporary file, and use that file as FILE * input.
+ */
+static inline
+FILE *lttng_fmemopen(void *buf, size_t size, const char *mode)
+{
+       char tmpname[PATH_MAX];
+       size_t len;
+       FILE *fp;
+       int ret;
+
+       /*
+        * Support reading only.
+        */
+       if (strcmp(mode, "rb") != 0) {
+               return NULL;
+       }
+       strncpy(tmpname, "/tmp/lttng-tmp-XXXXXX", PATH_MAX);
+       ret = mkstemp(tmpname);
+       if (ret < 0) {
+               return NULL;
+       }
+       /*
+        * We need to write to the file.
+        */
+       fp = fdopen(ret, "w+");
+       if (!fp) {
+               goto error_unlink;
+       }
+       /* Copy the entire buffer to the file */
+       len = fwrite(buf, sizeof(char), size, fp);
+       if (len != size) {
+               goto error_close;
+       }
+       ret = fseek(fp, 0L, SEEK_SET);
+       if (ret < 0) {
+               perror("fseek");
+               goto error_close;
+       }
+       /* We keep the handle open, but can unlink the file on the VFS. */
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               perror("unlink");
+       }
+       return fp;
+
+error_close:
+       ret = fclose(fp);
+       if (ret < 0) {
+               perror("close");
+       }
+error_unlink:
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               perror("unlink");
+       }
+       return NULL;
+}
+
+#endif /* LTTNG_HAVE_FMEMOPEN */
+
+#ifdef LTTNG_HAVE_OPEN_MEMSTREAM
+
+#include <stdio.h>
+
+static inline
+FILE *lttng_open_memstream(char **ptr, size_t *sizeloc)
+{
+       return open_memstream(ptr, sizeloc);
+}
+
+static inline
+int lttng_close_memstream(char **buf, size_t *size, FILE *fp)
+{
+       return fclose(fp);
+}
+
+#else /* LTTNG_HAVE_OPEN_MEMSTREAM */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * Fallback for systems which don't have open_memstream. Create FILE *
+ * with lttng_open_memstream, but require call to
+ * lttng_close_memstream to flush all data written to the FILE *
+ * into the buffer (which we allocate).
+ */
+static inline
+FILE *lttng_open_memstream(char **ptr, size_t *sizeloc)
+{
+       char tmpname[PATH_MAX];
+       int ret;
+       FILE *fp;
+
+       strncpy(tmpname, "/tmp/lttng-tmp-XXXXXX", PATH_MAX);
+       ret = mkstemp(tmpname);
+       if (ret < 0) {
+               return NULL;
+       }
+       fp = fdopen(ret, "w+");
+       if (!fp) {
+               goto error_unlink;
+       }
+       /*
+        * lttng_flush_memstream will update the buffer content
+        * with read from fp. No need to keep the file around, just the
+        * handle.
+        */
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               perror("unlink");
+       }
+       return fp;
+
+error_unlink:
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               perror("unlink");
+       }
+       return NULL;
+}
+
+/* Get file size, allocate buffer, copy. */
+static inline
+int lttng_close_memstream(char **buf, size_t *size, FILE *fp)
+{
+       size_t len, n;
+       long pos;
+       int ret;
+
+       ret = fflush(fp);
+       if (ret < 0) {
+               perror("fflush");
+               return ret;
+       }
+       ret = fseek(fp, 0L, SEEK_END);
+       if (ret < 0) {
+               perror("fseek");
+               return ret;
+       }
+       pos = ftell(fp);
+       if (ret < 0) {
+               perror("ftell");
+               return ret;
+       }
+       *size = pos;
+       /* add final \0 */
+       *buf = calloc(pos + 1, sizeof(char));
+       if (!*buf) {
+               return -ENOMEM;
+       }
+       ret = fseek(fp, 0L, SEEK_SET);
+       if (ret < 0) {
+               perror("fseek");
+               goto error_free;
+       }
+       /* Copy the entire file into the buffer */
+       n = 0;
+       clearerr(fp);
+       while (!feof(fp) && !ferror(fp) && (*size - n > 0)) {
+               len = fread(*buf, sizeof(char), *size - n, fp);
+               n += len;
+       }
+       if (n != *size) {
+               ret = -1;
+               goto error_close;
+       }
+       ret = fclose(fp);
+       if (ret < 0) {
+               perror("fclose");
+               return ret;
+       }
+       return 0;
+
+error_close:
+       ret = fclose(fp);
+       if (ret < 0) {
+               perror("fclose");
+       }
+error_free:
+       free(*buf);
+       *buf = NULL;
+       return ret;
+}
+
+#endif /* LTTNG_HAVE_OPEN_MEMSTREAM */
+
+#endif /* _LTTNG_CTL_MEMSTREAM_H */
index 79434cad5a4b9528d7b71b3bbb24335bdba335fe..2992afbf5bbd5898ec29bff56d2939e14e2f3ed9 100644 (file)
@@ -6,12 +6,17 @@ EXTRA_DIST = runall.sh run-kernel-tests.sh
 noinst_PROGRAMS = kernel_all_events_basic kernel_event_basic
 
 UTILS=../utils.h
-LIBLTTNG=$(top_srcdir)/src/lib/lttng-ctl/lttng-ctl.c \
-                $(top_srcdir)/src/common/sessiond-comm/sessiond-comm.c \
+LIBLTTNG=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
+
+SESSIONDSRC=$(top_srcdir)/src/common/sessiond-comm/sessiond-comm.c \
                 $(top_srcdir)/src/common/sessiond-comm/unix.c \
                 $(top_srcdir)/src/common/sessiond-comm/inet.c \
                 $(top_srcdir)/src/common/sessiond-comm/inet6.c
 
-kernel_all_events_basic_SOURCES = kernel_all_events_basic.c $(UTILS) $(LIBLTTNG)
+kernel_all_events_basic_SOURCES = kernel_all_events_basic.c $(UTILS) \
+               $(SESSIONDSRC)
+kernel_all_events_basic_LDADD = $(LIBLTTNG)
 
-kernel_event_basic_SOURCES = kernel_event_basic.c $(UTILS) $(LIBLTTNG)
+kernel_event_basic_SOURCES = kernel_event_basic.c $(UTILS) \
+               $(SESSIONDSRC)
+kernel_event_basic_LDADD = $(LIBLTTNG)
index 1275b9804c39a18f3f29bbd558447b1b1d804830..146bff250b0197004e3170cfb4953a948458c75a 100644 (file)
@@ -9,13 +9,19 @@ EXTRA_DIST = runall.sh run-ust-global-tests.sh
 noinst_PROGRAMS = ust_global_event_basic ust_global_event_wildcard
 
 UTILS=../utils.h
-LIBLTTNG=$(top_srcdir)/src/lib/lttng-ctl/lttng-ctl.c \
-                $(top_srcdir)/src/common/sessiond-comm/sessiond-comm.c \
+LIBLTTNG=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
+
+SESSIONDSRC=$(top_srcdir)/src/common/sessiond-comm/sessiond-comm.c \
                 $(top_srcdir)/src/common/sessiond-comm/unix.c \
                 $(top_srcdir)/src/common/sessiond-comm/inet.c \
                 $(top_srcdir)/src/common/sessiond-comm/inet6.c
 
-ust_global_event_wildcard_SOURCES = ust_global_event_wildcard.c $(UTILS) $(LIBLTTNG)
+ust_global_event_wildcard_SOURCES = ust_global_event_wildcard.c $(UTILS) \
+               $(SESSIONDSRC)
+ust_global_event_wildcard_LDADD = $(LIBLTTNG)
+
+ust_global_event_basic_SOURCES = ust_global_event_basic.c $(UTILS) \
+               $(SESSIONDSRC)
+ust_global_event_basic_LDADD = $(LIBLTTNG)
 
-ust_global_event_basic_SOURCES = ust_global_event_basic.c $(UTILS) $(LIBLTTNG)
 endif
This page took 0.0456 seconds and 4 git commands to generate.