X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Flib%2Flttng-ctl%2Flttng-ctl.c;h=fff602305ce9a13c2fb0b4dd1e350bf57af78f36;hb=1831ae68b70dece8e9b847081526495adbbf05e5;hp=085005c3940bd4d1c039996b83857f454a29cbf0;hpb=55c9e7cac24318259d4f2549c97f7577b7b52db4;p=lttng-tools.git diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index 085005c39..fff602305 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -4,20 +4,10 @@ * Linux Trace Toolkit Control Library * * Copyright (C) 2011 David Goulet - * Copyright (C) 2016 - Jérémie Galarneau + * Copyright (C) 2016 Jérémie Galarneau * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License, version 2.1 only, - * as published by the Free Software Foundation. + * SPDX-License-Identifier: LGPL-2.1-only * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define _LGPL_SOURCE @@ -46,27 +36,14 @@ #include #include #include +#include -#include "filter/filter-ast.h" -#include "filter/filter-parser.h" -#include "filter/filter-bytecode.h" -#include "filter/memstream.h" +#include +#include +#include +#include #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; \ @@ -905,7 +882,7 @@ static char *set_agent_filter(const char *filter, struct lttng_event *ev) /* Add loglevel filtering if any for the JUL domain. */ if (ev->loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) { - char *op; + const char *op; if (ev->loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) { op = ">="; @@ -939,133 +916,6 @@ error: 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. @@ -1169,10 +1019,14 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, } } - 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, @@ -1378,10 +1232,14 @@ int lttng_disable_event_ext(struct lttng_handle *handle, } } - 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 @@ -1606,98 +1464,6 @@ int lttng_disable_channel(struct lttng_handle *handle, const char *name) return lttng_ctl_ask_sessiond(&lsm, NULL); } -static int lttng_track_untrack_id(struct lttng_handle *handle, - enum lttng_tracker_type tracker_type, - const struct lttng_tracker_id *id, - enum lttcomm_sessiond_command cmd) -{ - struct lttcomm_session_msg lsm; - char *var_data = NULL; - size_t var_data_len = 0; - - /* NULL arguments are forbidden. No default values. */ - if (handle == NULL) { - return -LTTNG_ERR_INVALID; - } - - memset(&lsm, 0, sizeof(lsm)); - - lsm.cmd_type = cmd; - lsm.u.id_tracker.tracker_type = tracker_type; - lsm.u.id_tracker.id_type = id->type; - switch (id->type) { - case LTTNG_ID_ALL: - break; - case LTTNG_ID_VALUE: - lsm.u.id_tracker.u.value = id->value; - break; - case LTTNG_ID_STRING: - var_data = id->string; - var_data_len = strlen(var_data) + 1; /* Includes \0. */ - lsm.u.id_tracker.u.var_len = var_data_len; - break; - default: - return -LTTNG_ERR_INVALID; - } - - COPY_DOMAIN_PACKED(lsm.domain, handle->domain); - - lttng_ctl_copy_string(lsm.session.name, handle->session_name, - sizeof(lsm.session.name)); - - return lttng_ctl_ask_sessiond_varlen_no_cmd_header( - &lsm, var_data, var_data_len, NULL); -} - -/* - * Add ID to session tracker. - * Return 0 on success else a negative LTTng error code. - */ -int lttng_track_id(struct lttng_handle *handle, - enum lttng_tracker_type tracker_type, - const struct lttng_tracker_id *id) -{ - return lttng_track_untrack_id(handle, tracker_type, id, LTTNG_TRACK_ID); -} - -/* - * Remove ID from session tracker. - * Return 0 on success else a negative LTTng error code. - */ -int lttng_untrack_id(struct lttng_handle *handle, - enum lttng_tracker_type tracker_type, - const struct lttng_tracker_id *id) -{ - return lttng_track_untrack_id( - handle, tracker_type, id, LTTNG_UNTRACK_ID); -} - -/* - * Add PID to session tracker. - * Return 0 on success else a negative LTTng error code. - */ -int lttng_track_pid(struct lttng_handle *handle, int pid) -{ - struct lttng_tracker_id id; - - id.type = LTTNG_TRACKER_PID; - id.value = pid; - return lttng_track_id(handle, LTTNG_TRACKER_PID, &id); -} - -/* - * Remove PID from session tracker. - * Return 0 on success else a negative LTTng error code. - */ -int lttng_untrack_pid(struct lttng_handle *handle, int pid) -{ - struct lttng_tracker_id id; - - id.type = LTTNG_TRACKER_PID; - id.value = pid; - return lttng_untrack_id(handle, LTTNG_TRACKER_PID, &id); -} - /* * Lists all available tracepoints of domain. * Sets the contents of the events array. @@ -2923,15 +2689,14 @@ end: * * tracker_type is the type of tracker. * ids is set to an allocated array of IDs currently tracked. On - * success, ids and all the strings it contains must be freed by the caller. + * success, ids and contained ids must be freed/destroy by the caller. * nr_ids is set to the number of entries contained by the ids array. * * Returns 0 on success, else a negative LTTng error code. */ int lttng_list_tracker_ids(struct lttng_handle *handle, enum lttng_tracker_type tracker_type, - struct lttng_tracker_id **_ids, - size_t *_nr_ids) + struct lttng_tracker_ids **_ids) { int ret, i; struct lttcomm_session_msg lsm; @@ -2939,7 +2704,7 @@ int lttng_list_tracker_ids(struct lttng_handle *handle, char *cmd_payload = NULL, *p; size_t cmd_header_len; size_t nr_ids = 0; - struct lttng_tracker_id *ids = NULL; + struct lttng_tracker_ids *ids = NULL; if (handle == NULL) { return -LTTNG_ERR_INVALID; @@ -2968,7 +2733,7 @@ int lttng_list_tracker_ids(struct lttng_handle *handle, free(cmd_header); cmd_header = NULL; - ids = zmalloc(sizeof(*ids) * nr_ids); + ids = lttng_tracker_ids_create(nr_ids); if (!ids) { ret = -LTTNG_ERR_NOMEM; goto error; @@ -2978,42 +2743,44 @@ int lttng_list_tracker_ids(struct lttng_handle *handle, for (i = 0; i < nr_ids; i++) { struct lttcomm_tracker_id_header *tracker_id; struct lttng_tracker_id *id; + enum lttng_tracker_id_status status; tracker_id = (struct lttcomm_tracker_id_header *) p; p += sizeof(struct lttcomm_tracker_id_header); - id = &ids[i]; + id = lttng_tracker_ids_get_pointer_of_index(ids, i); + if (!id) { + ret = -LTTNG_ERR_INVALID; + goto error; + } - id->type = tracker_id->type; switch (tracker_id->type) { case LTTNG_ID_ALL: + status = lttng_tracker_id_set_all(id); break; case LTTNG_ID_VALUE: id->value = tracker_id->u.value; + status = lttng_tracker_id_set_value( + id, tracker_id->u.value); break; case LTTNG_ID_STRING: - id->string = strdup(p); - if (!id->string) { - ret = -LTTNG_ERR_NOMEM; - goto error; - } + status = lttng_tracker_id_set_string(id, p); p += tracker_id->u.var_data_len; break; default: goto error; } + + if (status != LTTNG_TRACKER_ID_STATUS_OK) { + ret = -LTTNG_ERR_INVALID; + goto error; + } } free(cmd_payload); *_ids = ids; - *_nr_ids = nr_ids; return 0; error: - if (ids) { - for (i = 0; i < nr_ids; i++) { - free(ids[i].string); - } - free(ids); - } + lttng_tracker_ids_destroy(ids); free(cmd_payload); free(cmd_header); return ret; @@ -3032,19 +2799,32 @@ error: int lttng_list_tracker_pids(struct lttng_handle *handle, int *_enabled, int32_t **_pids, size_t *_nr_pids) { - struct lttng_tracker_id *ids = NULL; - size_t nr_ids = 0; + struct lttng_tracker_ids *ids = NULL; + unsigned int nr_ids = 0; int *pids = NULL; int ret = 0, i; + enum lttng_tracker_id_status status; + const struct lttng_tracker_id *id; - ret = lttng_list_tracker_ids(handle, LTTNG_TRACKER_PID, &ids, &nr_ids); - if (ret < 0) + ret = lttng_list_tracker_ids(handle, LTTNG_TRACKER_PID, &ids); + if (ret < 0) { return ret; + } - if (nr_ids == 1 && ids[0].type == LTTNG_ID_ALL) { - *_enabled = 0; + status = lttng_tracker_ids_get_count(ids, &nr_ids); + if (status != LTTNG_TRACKER_ID_STATUS_OK) { + ret = -LTTNG_ERR_INVALID; goto end; } + + if (nr_ids == 1) { + id = lttng_tracker_ids_get_at_index(ids, 0); + if (id && lttng_tracker_id_get_type(id) == LTTNG_ID_ALL) { + *_enabled = 0; + goto end; + } + } + *_enabled = 1; pids = zmalloc(nr_ids * sizeof(*pids)); @@ -3053,21 +2833,17 @@ int lttng_list_tracker_pids(struct lttng_handle *handle, goto end; } for (i = 0; i < nr_ids; i++) { - struct lttng_tracker_id *id = &ids[i]; - - if (id->type != LTTNG_ID_VALUE) { + id = lttng_tracker_ids_get_at_index(ids, i); + status = lttng_tracker_id_get_value(id, &pids[i]); + if (status != LTTNG_TRACKER_ID_STATUS_OK) { ret = -LTTNG_ERR_UNK; goto end; } - pids[i] = id->value; } *_pids = pids; *_nr_pids = nr_ids; end: - for (i = 0; i < nr_ids; i++) { - free(ids[i].string); - } - free(ids); + lttng_tracker_ids_destroy(ids); if (ret < 0) { free(pids); } @@ -3145,8 +2921,15 @@ end: 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) { @@ -3159,23 +2942,91 @@ int lttng_register_trigger(struct lttng_trigger *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; @@ -3192,7 +3043,7 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger) goto end; } - ret = lttng_trigger_serialize(trigger, &buffer); + ret = lttng_trigger_serialize(trigger, &buffer, NULL); if (ret < 0) { ret = -LTTNG_ERR_UNK; goto end; @@ -3208,6 +3059,174 @@ 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; +} + +static int lttng_track_untrack_id(struct lttng_handle *handle, + enum lttng_tracker_type tracker_type, + const struct lttng_tracker_id *id, + enum lttcomm_sessiond_command cmd) +{ + int ret; + struct lttcomm_session_msg lsm; + const char *var_data = NULL; + size_t var_data_len = 0; + int value; + enum lttng_tracker_id_status status; + + /* NULL arguments are forbidden. No default values. */ + if (handle == NULL) { + goto error; + } + + memset(&lsm, 0, sizeof(lsm)); + + lsm.cmd_type = cmd; + lsm.u.id_tracker.tracker_type = tracker_type; + lsm.u.id_tracker.id_type = lttng_tracker_id_get_type(id); + switch (lsm.u.id_tracker.id_type) { + case LTTNG_ID_ALL: + break; + case LTTNG_ID_VALUE: + status = lttng_tracker_id_get_value(id, &value); + if (status != LTTNG_TRACKER_ID_STATUS_OK) { + goto error; + } + lsm.u.id_tracker.u.value = value; + break; + case LTTNG_ID_STRING: + status = lttng_tracker_id_get_string(id, &var_data); + if (status != LTTNG_TRACKER_ID_STATUS_OK) { + goto error; + } + var_data_len = strlen(var_data) + 1; /* Includes \0. */ + lsm.u.id_tracker.u.var_len = var_data_len; + break; + default: + goto error; + } + + COPY_DOMAIN_PACKED(lsm.domain, handle->domain); + + lttng_ctl_copy_string(lsm.session.name, handle->session_name, + sizeof(lsm.session.name)); + + ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header( + &lsm, (char *) var_data, var_data_len, NULL); + return ret; +error: + return -LTTNG_ERR_INVALID; +} + +/* + * Add ID to session tracker. + * Return 0 on success else a negative LTTng error code. + */ +int lttng_track_id(struct lttng_handle *handle, + enum lttng_tracker_type tracker_type, + const struct lttng_tracker_id *id) +{ + return lttng_track_untrack_id(handle, tracker_type, id, LTTNG_TRACK_ID); +} + +/* + * Remove ID from session tracker. + * Return 0 on success else a negative LTTng error code. + */ +int lttng_untrack_id(struct lttng_handle *handle, + enum lttng_tracker_type tracker_type, + const struct lttng_tracker_id *id) +{ + return lttng_track_untrack_id( + handle, tracker_type, id, LTTNG_UNTRACK_ID); +} + +/* + * Add PID to session tracker. + * Return 0 on success else a negative LTTng error code. + */ +int lttng_track_pid(struct lttng_handle *handle, int pid) +{ + int ret; + struct lttng_tracker_id *id = NULL; + enum lttng_tracker_id_status status; + + id = lttng_tracker_id_create(); + status = lttng_tracker_id_set_value(id, pid); + if (status == LTTNG_TRACKER_ID_STATUS_INVALID) { + ret = -LTTNG_ERR_INVALID; + goto error; + } + + ret = lttng_track_id(handle, LTTNG_TRACKER_PID, id); +error: + lttng_tracker_id_destroy(id); + return ret; +} + +/* + * Remove PID from session tracker. + * Return 0 on success else a negative LTTng error code. + */ +int lttng_untrack_pid(struct lttng_handle *handle, int pid) +{ + int ret; + struct lttng_tracker_id *id = NULL; + enum lttng_tracker_id_status status; + + id = lttng_tracker_id_create(); + status = lttng_tracker_id_set_value(id, pid); + if (status == LTTNG_TRACKER_ID_STATUS_INVALID) { + ret = -LTTNG_ERR_INVALID; + goto error; + } + + ret = lttng_untrack_id(handle, LTTNG_TRACKER_PID, id); +error: + lttng_tracker_id_destroy(id); + return ret; +} + /* * lib constructor. */