#include <string.h>
#include <unistd.h>
+#include <common/bytecode/bytecode.h>
#include <common/common.h>
#include <common/compat/string.h>
#include <common/defaults.h>
#include <lttng/trigger/trigger-internal.h>
#include <lttng/userspace-probe-internal.h>
-#include "filter/filter-ast.h"
-#include "filter/filter-parser.h"
-#include "filter/filter-bytecode.h"
-#include "filter/memstream.h"
+#include <common/filter/filter-ast.h>
+#include <common/filter/filter-parser.h>
+#include <common/filter/memstream.h>
#include "lttng-ctl-helper.h"
-#ifdef DEBUG
-static const int print_xml = 1;
-#define dbg_printf(fmt, args...) \
- printf("[debug liblttng-ctl] " fmt, ## args)
-#else
-static 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
-
#define COPY_DOMAIN_PACKED(dst, src) \
do { \
struct lttng_domain _tmp_domain; \
return NULL;
}
-/*
- * Generate the filter bytecode from a given filter expression string. Put the
- * newly allocated parser context in ctxp and populate the lsm object with the
- * expression len.
- *
- * Return 0 on success else a LTTNG_ERR_* code and ctxp is untouched.
- */
-static int generate_filter(char *filter_expression,
- struct lttcomm_session_msg *lsm, struct filter_parser_ctx **ctxp)
-{
- int ret;
- struct filter_parser_ctx *ctx = NULL;
- FILE *fmem = NULL;
-
- assert(filter_expression);
- assert(lsm);
- assert(ctxp);
-
- /*
- * 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");
- ret = -LTTNG_ERR_FILTER_NOMEM;
- goto error;
- }
- ctx = filter_parser_ctx_alloc(fmem);
- if (!ctx) {
- fprintf(stderr, "Error allocating parser\n");
- ret = -LTTNG_ERR_FILTER_NOMEM;
- goto filter_alloc_error;
- }
- ret = filter_parser_ctx_append_ast(ctx);
- if (ret) {
- fprintf(stderr, "Parse error\n");
- ret = -LTTNG_ERR_FILTER_INVAL;
- 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 = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
- }
-
- dbg_printf("Generating IR... ");
- fflush(stdout);
- ret = filter_visitor_ir_generate(ctx);
- if (ret) {
- fprintf(stderr, "Generate IR error\n");
- ret = -LTTNG_ERR_FILTER_INVAL;
- 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 = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
-
- /* Normalize globbing patterns in the expression. */
- ret = filter_visitor_ir_normalize_glob_patterns(ctx);
- if (ret) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
-
- /* Validate strings used as literals in the expression. */
- ret = filter_visitor_ir_validate_string(ctx);
- if (ret) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
-
- /* Validate globbing patterns in the expression. */
- ret = filter_visitor_ir_validate_globbing(ctx);
- if (ret) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- 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 = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
- dbg_printf("done\n");
- dbg_printf("Size of bytecode generated: %u bytes.\n",
- bytecode_get_len(&ctx->bytecode->b));
-
- lsm->u.enable.bytecode_len = sizeof(ctx->bytecode->b)
- + bytecode_get_len(&ctx->bytecode->b);
- lsm->u.enable.expression_len = strlen(filter_expression) + 1;
-
- /* No need to keep the memory stream. */
- if (fclose(fmem) != 0) {
- PERROR("fclose");
- }
-
- *ctxp = ctx;
- return 0;
-
-parse_error:
- filter_ir_free(ctx);
- filter_parser_ctx_free(ctx);
-filter_alloc_error:
- if (fclose(fmem) != 0) {
- PERROR("fclose");
- }
-error:
- return ret;
-}
-
/*
* Enable event(s) for a channel, possibly with exclusions and a filter.
* If no event name is specified, all events are enabled.
}
}
- ret = generate_filter(filter_expression, &lsm, &ctx);
+ ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
if (ret) {
goto filter_error;
}
+
+ lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b)
+ + bytecode_get_len(&ctx->bytecode->b);
+ lsm.u.enable.expression_len = strlen(filter_expression) + 1;
}
ret = lttng_dynamic_buffer_set_capacity(&send_buffer,
}
}
- ret = generate_filter(filter_expression, &lsm, &ctx);
+ ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
if (ret) {
goto filter_error;
}
+
+ lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b)
+ + bytecode_get_len(&ctx->bytecode->b);
+ lsm.u.enable.expression_len = strlen(filter_expression) + 1;
}
varlen_data = zmalloc(lsm.u.disable.bytecode_len
int lttng_register_trigger(struct lttng_trigger *trigger)
{
int ret;
+ int reply_ret;
struct lttcomm_session_msg lsm;
struct lttng_dynamic_buffer buffer;
+ void *reply = NULL;
+ struct lttng_buffer_view reply_view;
+ struct lttng_trigger *reply_trigger = NULL;
+ bool send_fd = false;
+ int fd_to_send;
+ enum lttng_domain_type domain_type;
lttng_dynamic_buffer_init(&buffer);
if (!trigger) {
goto end;
}
- ret = lttng_trigger_serialize(trigger, &buffer);
+ domain_type = lttng_trigger_get_underlying_domain_type_restriction(
+ trigger);
+
+ ret = lttng_trigger_serialize(trigger, &buffer, &fd_to_send);
if (ret < 0) {
ret = -LTTNG_ERR_UNK;
goto end;
}
+ if (getenv("LTTNG_REGISTER_TRIGGER_DRY_RUN")) {
+ /*
+ * Don't really send the request, just deserialize, validate
+ * that it is equal to the original trigger (to test
+ * serialization and deserialization), and return.
+ */
+ struct lttng_buffer_view bv;
+ ssize_t sz;
+
+ bv = lttng_buffer_view_from_dynamic_buffer(&buffer, 0, -1);
+ sz = lttng_trigger_create_from_buffer(&bv, &reply_trigger);
+ if (sz != bv.size) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ if (!reply_trigger) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ if (!lttng_trigger_is_equal(trigger, reply_trigger)) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ /* Give it a dummy name. */
+ lttng_trigger_set_name(trigger, "yop");
+
+ ret = 0;
+ goto end;
+ }
+
+ send_fd = fd_to_send >= 0;
+
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_REGISTER_TRIGGER;
+ lsm.domain.type = domain_type;
lsm.u.trigger.length = (uint32_t) buffer.size;
- ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, buffer.data,
- buffer.size, NULL);
+ reply_ret = lttng_ctl_ask_sessiond_fds_varlen_no_cmd_header(&lsm,
+ send_fd ? &fd_to_send : NULL,
+ send_fd ? 1 : 0,
+ buffer.data,
+ buffer.size,
+ &reply);
+ if (reply_ret < 0) {
+ ret = reply_ret;
+ goto end;
+ } else if (reply_ret == 0) {
+ /* Socket unexpectedly closed by the session daemon. */
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ reply_view = lttng_buffer_view_init(reply, 0, reply_ret);
+ ret = lttng_trigger_create_from_buffer(&reply_view, &reply_trigger);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ ret = lttng_trigger_assign(trigger, reply_trigger);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ ret = 0;
end:
+ free(reply);
lttng_dynamic_buffer_reset(&buffer);
+ lttng_trigger_destroy(reply_trigger);
return ret;
}
-int lttng_unregister_trigger(struct lttng_trigger *trigger)
+int lttng_unregister_trigger(const struct lttng_trigger *trigger)
{
int ret;
struct lttcomm_session_msg lsm;
goto end;
}
- ret = lttng_trigger_serialize(trigger, &buffer);
+ ret = lttng_trigger_serialize(trigger, &buffer, NULL);
if (ret < 0) {
ret = -LTTNG_ERR_UNK;
goto end;
return ret;
}
+/*
+ * Ask the session daemon for all registered triggers.
+ * Allocate a lttng_triggers collection.
+ * On error, returns a negative value.
+ */
+int lttng_list_triggers(struct lttng_triggers **triggers)
+{
+ int ret;
+ int reply_ret;
+ struct lttcomm_session_msg lsm;
+ struct lttng_buffer_view reply_view;
+ struct lttng_triggers *local_triggers = NULL;
+ void *reply = NULL;
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_LIST_TRIGGERS;
+
+ reply_ret = lttng_ctl_ask_sessiond(&lsm, &reply);
+ if (reply_ret < 0) {
+ ret = reply_ret;
+ goto end;
+ } else if (reply_ret == 0) {
+ /* Socket unexpectedly closed by the session daemon. */
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ reply_view = lttng_buffer_view_init(reply, 0, reply_ret);
+ ret = lttng_triggers_create_from_buffer(&reply_view, &local_triggers);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ *triggers = local_triggers;
+ local_triggers = NULL;
+ ret = 0;
+end:
+ free(reply);
+ free(local_triggers);
+ return ret;
+}
+
/*
* lib constructor.
*/