X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fbin%2Flttng%2Fcommands%2Fenable_events.cpp;h=b081adeeed7f3f68d7d97f57722002091c40bef0;hb=HEAD;hp=50854faaa7141a918a3c605d7bf802b9e214f353;hpb=48a4000561343808724f7cb5fa8c131877489ccd;p=lttng-tools.git diff --git a/src/bin/lttng/commands/enable_events.cpp b/src/bin/lttng/commands/enable_events.cpp index 50854faaa..b081adeee 100644 --- a/src/bin/lttng/commands/enable_events.cpp +++ b/src/bin/lttng/commands/enable_events.cpp @@ -1,62 +1,82 @@ /* - * Copyright (C) 2011 David Goulet + * Copyright (C) 2011 EfficiOS Inc. * * SPDX-License-Identifier: GPL-2.0-only * */ #define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include #include +#include #include #include +#include #include #include #include -#include -#include - -#include -#include -#include -#include -#include +#include /* Mi dependancy */ -#include +#include "../command.hpp" +#include "../loglevel.hpp" +#include "../uprobe.hpp" -#include -#include +#include -#include "../command.h" -#include "../loglevel.h" -#include "../uprobe.h" +#include +#include #if (LTTNG_SYMBOL_NAME_LEN == 256) -#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255" +#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255" #endif -static char *opt_event_list; -static int opt_event_type; -static const char *opt_loglevel; -static int opt_loglevel_type; -static int opt_kernel; -static char *opt_session_name; -static int opt_userspace; -static int opt_jul; -static int opt_log4j; -static int opt_python; -static int opt_enable_all; -static char *opt_probe; -static char *opt_userspace_probe; -static char *opt_function; -static char *opt_channel_name; -static char *opt_filter; -static char *opt_exclude; +namespace { +void _mi_lttng_writer_deleter_func(mi_writer *writer) +{ + if (writer && mi_lttng_writer_destroy(writer)) { + LTTNG_THROW_ERROR("Failed to destroy mi_writer instance"); + } +} + +using mi_writer_uptr = std::unique_ptr< + mi_writer, + lttng::memory::create_deleter_class::deleter>; +using event_rule_patterns = std::vector; + +int opt_event_type; +const char *opt_loglevel; +int opt_loglevel_type; +int opt_kernel; +char *opt_session_name; +int opt_userspace; +int opt_jul; +int opt_log4j; +int opt_python; +int opt_enable_all; +char *opt_probe; +char *opt_userspace_probe; +char *opt_function; +char *opt_channel_name; +char *opt_filter; +char *opt_exclude; + +struct lttng_handle *handle; +mi_writer_uptr writer; #ifdef LTTNG_EMBED_HELP static const char help_msg[] = #include -; + ; #endif enum { @@ -74,52 +94,58 @@ enum { OPT_EXCLUDE, }; -static struct lttng_handle *handle; -static struct mi_writer *writer; - -static struct poptOption long_options[] = { +struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, - {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0}, - {"all", 'a', POPT_ARG_VAL, &opt_enable_all, 1, 0, 0}, - {"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0}, - {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0}, - {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0}, - {"jul", 'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0}, - {"log4j", 'l', POPT_ARG_VAL, &opt_log4j, 1, 0, 0}, - {"python", 'p', POPT_ARG_VAL, &opt_python, 1, 0, 0}, - {"tracepoint", 0, POPT_ARG_NONE, 0, OPT_TRACEPOINT, 0, 0}, - {"probe", 0, POPT_ARG_STRING, &opt_probe, OPT_PROBE, 0, 0}, - {"userspace-probe",0, POPT_ARG_STRING, &opt_userspace_probe, OPT_USERSPACE_PROBE, 0, 0}, - {"function", 0, POPT_ARG_STRING, &opt_function, OPT_FUNCTION, 0, 0}, - {"syscall", 0, POPT_ARG_NONE, 0, OPT_SYSCALL, 0, 0}, - {"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}, - {"exclude", 'x', POPT_ARG_STRING, &opt_exclude, OPT_EXCLUDE, 0, 0}, - {0, 0, 0, 0, 0, 0, 0} + { "help", 'h', POPT_ARG_NONE, nullptr, OPT_HELP, nullptr, nullptr }, + { "session", 's', POPT_ARG_STRING, &opt_session_name, 0, nullptr, nullptr }, + { "all", 'a', POPT_ARG_VAL, &opt_enable_all, 1, nullptr, nullptr }, + { "channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, nullptr, nullptr }, + { "kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, nullptr, nullptr }, + { "userspace", 'u', POPT_ARG_NONE, nullptr, OPT_USERSPACE, nullptr, nullptr }, + { "jul", 'j', POPT_ARG_VAL, &opt_jul, 1, nullptr, nullptr }, + { "log4j", 'l', POPT_ARG_VAL, &opt_log4j, 1, nullptr, nullptr }, + { "python", 'p', POPT_ARG_VAL, &opt_python, 1, nullptr, nullptr }, + { "tracepoint", 0, POPT_ARG_NONE, nullptr, OPT_TRACEPOINT, nullptr, nullptr }, + { "probe", 0, POPT_ARG_STRING, &opt_probe, OPT_PROBE, nullptr, nullptr }, + { "userspace-probe", + 0, + POPT_ARG_STRING, + &opt_userspace_probe, + OPT_USERSPACE_PROBE, + nullptr, + nullptr }, + { "function", 0, POPT_ARG_STRING, &opt_function, OPT_FUNCTION, nullptr, nullptr }, + { "syscall", 0, POPT_ARG_NONE, nullptr, OPT_SYSCALL, nullptr, nullptr }, + { "loglevel", 0, POPT_ARG_STRING, nullptr, OPT_LOGLEVEL, nullptr, nullptr }, + { "loglevel-only", 0, POPT_ARG_STRING, nullptr, OPT_LOGLEVEL_ONLY, nullptr, nullptr }, + { "list-options", 0, POPT_ARG_NONE, nullptr, OPT_LIST_OPTIONS, nullptr, nullptr }, + { "filter", 'f', POPT_ARG_STRING, &opt_filter, OPT_FILTER, nullptr, nullptr }, + { "exclude", 'x', POPT_ARG_STRING, &opt_exclude, OPT_EXCLUDE, nullptr, nullptr }, + { nullptr, 0, 0, nullptr, 0, nullptr, nullptr } }; /* * Parse probe options. */ -static int parse_probe_opts(struct lttng_event *ev, char *opt) +int parse_probe_opts(struct lttng_event *ev, char *opt) { int ret = CMD_SUCCESS; int match; char s_hex[19]; -#define S_HEX_LEN_SCANF_IS_A_BROKEN_API "18" /* 18 is (19 - 1) (\0 is extra) */ +#define S_HEX_LEN_SCANF_IS_A_BROKEN_API "18" /* 18 is (19 - 1) (\0 is extra) */ char name[LTTNG_SYMBOL_NAME_LEN]; - if (opt == NULL) { + if (opt == nullptr) { ret = CMD_ERROR; goto end; } /* Check for symbol+offset */ - match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API - "[^'+']+%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", name, s_hex); + match = sscanf(opt, + "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API + "[^'+']+%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", + name, + s_hex); if (match == 2) { strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN); ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; @@ -129,7 +155,7 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt) ret = CMD_ERROR; goto end; } - ev->attr.probe.offset = strtoul(s_hex, NULL, 0); + ev->attr.probe.offset = strtoull(s_hex, nullptr, 0); DBG("probe offset %" PRIu64, ev->attr.probe.offset); ev->attr.probe.addr = 0; goto end; @@ -137,8 +163,7 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt) /* Check for symbol */ if (isalpha(name[0]) || name[0] == '_') { - match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "s", - name); + match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "s", name); if (match == 1) { strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN); ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; @@ -159,11 +184,11 @@ static int parse_probe_opts(struct lttng_event *ev, char *opt) * is in hexadecimal and can be 1 to 9 if it's in decimal. */ if (*s_hex == '\0' || !isdigit(*s_hex)) { - ERR("Invalid probe description %s", s_hex); + ERR("Invalid probe description `%s`", s_hex); ret = CMD_ERROR; goto end; } - ev->attr.probe.addr = strtoul(s_hex, NULL, 0); + ev->attr.probe.addr = strtoull(s_hex, nullptr, 0); DBG("probe addr %" PRIu64, ev->attr.probe.addr); ev->attr.probe.offset = 0; memset(ev->attr.probe.symbol_name, 0, LTTNG_SYMBOL_NAME_LEN); @@ -177,22 +202,19 @@ end: return ret; } -static const char *print_channel_name(const char *name) { - return name ? : DEFAULT_CHANNEL_NAME; + return name ?: DEFAULT_CHANNEL_NAME; } -static const char *print_raw_channel_name(const char *name) { - return name ? : ""; + return name ?: ""; } /* * Mi print exlcusion list */ -static int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusions) { int ret; @@ -206,24 +228,24 @@ int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusions) goto end; } - ret = mi_lttng_writer_open_element(writer, config_element_exclusions); + ret = mi_lttng_writer_open_element(writer.get(), config_element_exclusions); if (ret) { goto end; } for (i = 0; i < count; i++) { - const char *exclusion = (const char *) lttng_dynamic_pointer_array_get_pointer( - exclusions, i); + const char *exclusion = + (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i); - ret = mi_lttng_writer_write_element_string(writer, - config_element_exclusion, exclusion); + ret = mi_lttng_writer_write_element_string( + writer.get(), config_element_exclusion, exclusion); if (ret) { goto end; } } /* Close exclusions element */ - ret = mi_lttng_writer_close_element(writer); + ret = mi_lttng_writer_close_element(writer.get()); end: return ret; @@ -232,7 +254,6 @@ end: /* * Return allocated string for pretty-printing exclusion names. */ -static char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions) { int length = 0; @@ -247,26 +268,26 @@ char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions) /* Calculate total required length. */ for (i = 0; i < count; i++) { - const char *exclusion = (const char *) lttng_dynamic_pointer_array_get_pointer( - exclusions, i); + const char *exclusion = + (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i); length += strlen(exclusion) + 4; } length += sizeof(preamble); - ret = (char *) zmalloc(length); + ret = calloc(length); if (!ret) { - return NULL; + return nullptr; } strncpy(ret, preamble, length); for (i = 0; i < count; i++) { - const char *exclusion = (const char *) lttng_dynamic_pointer_array_get_pointer( - exclusions, i); + const char *exclusion = + (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i); - strcat(ret, "\""); + strcat(ret, "`"); strcat(ret, exclusion); - strcat(ret, "\""); + strcat(ret, "`"); if (i != count - 1) { strcat(ret, ", "); } @@ -275,12 +296,11 @@ char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions) return ret; } -static -int check_exclusion_subsets(const char *event_name, const char *exclusion) +int check_exclusion_subsets(const char *pattern, const char *exclusion) { bool warn = false; int ret = 0; - const char *e = event_name; + const char *e = pattern; const char *x = exclusion; /* Scan both the excluder and the event letter by letter */ @@ -298,8 +318,9 @@ int check_exclusion_subsets(const char *event_name, const char *exclusion) if (*x == '*') { /* Event is a subset of the excluder */ - ERR("Event %s: %s excludes all events from %s", - event_name, exclusion, event_name); + ERR("Exclusion pattern `%s` excludes all events from `%s`", + exclusion, + pattern); goto error; } @@ -311,7 +332,7 @@ int check_exclusion_subsets(const char *event_name, const char *exclusion) goto end; } -cmp_chars: + cmp_chars: if (*x != *e) { warn = true; break; @@ -328,63 +349,17 @@ error: end: if (warn) { - WARN("Event %s: %s does not exclude any events from %s", - event_name, exclusion, event_name); - } - - return ret; -} - -int validate_exclusion_list(const char *event_name, - const struct lttng_dynamic_pointer_array *exclusions) -{ - int ret; - - /* Event name must be a valid globbing pattern to allow exclusions. */ - if (!strutils_is_star_glob_pattern(event_name)) { - ERR("Event %s: Exclusions can only be used with a globbing pattern", - event_name); - goto error; - } - - /* - * If the event name is a star-at-end only globbing pattern, - * then we can validate the individual exclusions. Otherwise - * all exclusions are passed to the session daemon. - */ - if (strutils_is_star_at_the_end_only_glob_pattern(event_name)) { - size_t i, num_exclusions; - - num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions); - - for (i = 0; i < num_exclusions; i++) { - const char *exclusion = - (const char *) lttng_dynamic_pointer_array_get_pointer( - exclusions, i); - - if (!strutils_is_star_glob_pattern(exclusion) || - strutils_is_star_at_the_end_only_glob_pattern(exclusion)) { - ret = check_exclusion_subsets(event_name, exclusion); - if (ret) { - goto error; - } - } - } + WARN("Exclusion pattern `%s` does not exclude any event from `%s`", + exclusion, + pattern); } - ret = 0; - goto end; - -error: - ret = -1; - -end: return ret; } -static int create_exclusion_list_and_validate(const char *event_name, - const char *exclusions_arg, - struct lttng_dynamic_pointer_array *exclusions) +int create_exclusion_list_and_validate(const char *pattern, + const char *exclusions_arg, + struct lttng_dynamic_pointer_array *exclusions) { int ret = 0; @@ -394,8 +369,7 @@ static int create_exclusion_list_and_validate(const char *event_name, goto error; } - if (validate_exclusion_list(event_name, exclusions) != - 0) { + if (validate_exclusion_list(pattern, exclusions) != 0) { goto error; } @@ -409,18 +383,18 @@ end: return ret; } -static void warn_on_truncated_exclusion_names(const struct lttng_dynamic_pointer_array *exclusions, - int *warn) +void warn_on_truncated_exclusion_names(const struct lttng_dynamic_pointer_array *exclusions, + int *warn) { size_t i; const size_t num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions); for (i = 0; i < num_exclusions; i++) { - const char * const exclusion = (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i); + const char *const exclusion = + (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i); if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) { - WARN("Event exclusion \"%s\" will be truncated", - exclusion); + WARN("Event exclusion \"%s\" will be truncated", exclusion); *warn = 1; } } @@ -430,17 +404,17 @@ static void warn_on_truncated_exclusion_names(const struct lttng_dynamic_pointer * Enabling event using the lttng API. * Note: in case of error only the last error code will be return. */ -static int enable_events(char *session_name) +int enable_events(const std::string& session_name, const event_rule_patterns& patterns) { int ret = CMD_SUCCESS, command_ret = CMD_SUCCESS; int error_holder = CMD_SUCCESS, warn = 0, error = 0, success = 1; - char *event_name, *channel_name = NULL; + char *channel_name = nullptr; struct lttng_event *ev; struct lttng_domain dom = {}; struct lttng_dynamic_pointer_array exclusions; - struct lttng_userspace_probe_location *uprobe_loc = NULL; + struct lttng_userspace_probe_location *uprobe_loc = nullptr; - lttng_dynamic_pointer_array_init(&exclusions, NULL); + lttng_dynamic_pointer_array_init(&exclusions, nullptr); ev = lttng_event_create(); if (!ev) { @@ -450,7 +424,7 @@ static int enable_events(char *session_name) if (opt_kernel) { if (opt_loglevel) { - WARN("Kernel loglevels are not supported."); + WARN("Kernel log levels are not supported"); } } @@ -485,8 +459,8 @@ static int enable_events(char *session_name) case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: case LTTNG_DOMAIN_PYTHON: - ERR("Event name exclusions are not yet implemented for %s events", - lttng_domain_type_str(dom.type)); + ERR("Event name exclusions are not supported for %s event rules", + lttng_domain_type_str(dom.type)); ret = CMD_ERROR; goto error; case LTTNG_DOMAIN_UST: @@ -511,8 +485,8 @@ static int enable_events(char *session_name) case LTTNG_EVENT_PROBE: case LTTNG_EVENT_USERSPACE_PROBE: case LTTNG_EVENT_FUNCTION: - ERR("Filter expressions are not supported for %s events", - get_event_type_str((lttng_event_type) opt_event_type)); + ERR("Filter expressions are not supported for %s event rules", + get_event_type_str((lttng_event_type) opt_event_type)); ret = CMD_ERROR; goto error; default: @@ -523,8 +497,8 @@ static int enable_events(char *session_name) channel_name = opt_channel_name; - handle = lttng_create_handle(session_name, &dom); - if (handle == NULL) { + handle = lttng_create_handle(session_name.c_str(), &dom); + if (handle == nullptr) { ret = -1; goto error; } @@ -532,303 +506,29 @@ static int enable_events(char *session_name) /* Prepare Mi */ if (lttng_opt_mi) { /* Open a events element */ - ret = mi_lttng_writer_open_element(writer, config_element_events); + ret = mi_lttng_writer_open_element(writer.get(), config_element_events); if (ret) { ret = CMD_ERROR; goto error; } } - if (opt_enable_all) { - /* Default setup for enable all */ - if (opt_kernel) { - ev->type = (lttng_event_type) opt_event_type; - strcpy(ev->name, "*"); - /* kernel loglevels not implemented */ - ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; - } else { - ev->type = LTTNG_EVENT_TRACEPOINT; - strcpy(ev->name, "*"); - ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type; - if (opt_loglevel) { - int name_search_ret; - - LTTNG_ASSERT(opt_userspace || opt_jul || opt_log4j || opt_python); - - if (opt_userspace) { - enum lttng_loglevel loglevel; - - name_search_ret = loglevel_name_to_value(opt_loglevel, &loglevel); - ev->loglevel = (int) loglevel; - } else if (opt_jul) { - enum lttng_loglevel_jul loglevel; - - name_search_ret = loglevel_jul_name_to_value(opt_loglevel, &loglevel); - ev->loglevel = (int) loglevel; - } else if (opt_log4j) { - enum lttng_loglevel_log4j loglevel; - - name_search_ret = loglevel_log4j_name_to_value(opt_loglevel, &loglevel); - ev->loglevel = (int) loglevel; - } else { - /* python domain. */ - enum lttng_loglevel_python loglevel; - - name_search_ret = loglevel_python_name_to_value(opt_loglevel, &loglevel); - ev->loglevel = (int) loglevel; - } - - if (name_search_ret == -1) { - ERR("Unknown loglevel %s", opt_loglevel); - ret = -LTTNG_ERR_INVALID; - goto error; - } - } else { - LTTNG_ASSERT(opt_userspace || opt_jul || opt_log4j || opt_python); - if (opt_userspace) { - ev->loglevel = -1; - } else if (opt_jul) { - ev->loglevel = LTTNG_LOGLEVEL_JUL_ALL; - } else if (opt_log4j) { - ev->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL; - } else if (opt_python) { - ev->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG; - } - } - } - - if (opt_exclude) { - ret = create_exclusion_list_and_validate("*", - opt_exclude, &exclusions); - if (ret) { - ret = CMD_ERROR; - goto error; - } - - ev->exclusion = 1; - warn_on_truncated_exclusion_names(&exclusions, - &warn); - } - if (!opt_filter) { - ret = lttng_enable_event_with_exclusions(handle, - ev, channel_name, - NULL, - lttng_dynamic_pointer_array_get_count(&exclusions), - (char **) exclusions.array.buffer.data); - if (ret < 0) { - switch (-ret) { - case LTTNG_ERR_KERN_EVENT_EXIST: - WARN("Kernel events already enabled (channel %s, session %s)", - print_channel_name(channel_name), session_name); - warn = 1; - break; - case LTTNG_ERR_TRACE_ALREADY_STARTED: - { - const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once."; - ERR("Events: %s (channel %s, session %s)", - msg, - print_channel_name(channel_name), - session_name); - error = 1; - break; - } - default: - ERR("Events: %s (channel %s, session %s)", - lttng_strerror(ret), - ret == -LTTNG_ERR_NEED_CHANNEL_NAME - ? print_raw_channel_name(channel_name) - : print_channel_name(channel_name), - session_name); - error = 1; - break; - } - goto end; - } - - switch (opt_event_type) { - case LTTNG_EVENT_TRACEPOINT: - if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) { - char *exclusion_string = print_exclusions(&exclusions); - - if (!exclusion_string) { - PERROR("Cannot allocate exclusion_string"); - error = 1; - goto end; - } - MSG("All %s tracepoints%s are enabled in channel %s for loglevel %s", - lttng_domain_type_str(dom.type), - exclusion_string, - print_channel_name(channel_name), - opt_loglevel); - free(exclusion_string); - } else { - char *exclusion_string = print_exclusions(&exclusions); - - if (!exclusion_string) { - PERROR("Cannot allocate exclusion_string"); - error = 1; - goto end; - } - MSG("All %s tracepoints%s are enabled in channel %s", - lttng_domain_type_str(dom.type), - exclusion_string, - print_channel_name(channel_name)); - free(exclusion_string); - } - break; - case LTTNG_EVENT_SYSCALL: - if (opt_kernel) { - MSG("All %s system calls are enabled in channel %s", - lttng_domain_type_str(dom.type), - print_channel_name(channel_name)); - } - break; - case LTTNG_EVENT_ALL: - if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) { - char *exclusion_string = print_exclusions(&exclusions); - - if (!exclusion_string) { - PERROR("Cannot allocate exclusion_string"); - error = 1; - goto end; - } - MSG("All %s events%s are enabled in channel %s for loglevel %s", - lttng_domain_type_str(dom.type), - exclusion_string, - print_channel_name(channel_name), - opt_loglevel); - free(exclusion_string); - } else { - char *exclusion_string = print_exclusions(&exclusions); - - if (!exclusion_string) { - PERROR("Cannot allocate exclusion_string"); - error = 1; - goto end; - } - MSG("All %s events%s are enabled in channel %s", - lttng_domain_type_str(dom.type), - exclusion_string, - print_channel_name(channel_name)); - free(exclusion_string); - } - break; - default: - /* - * We should not be here since lttng_enable_event should have - * failed on the event type. - */ - goto error; - } - } - - if (opt_filter) { - command_ret = lttng_enable_event_with_exclusions(handle, ev, channel_name, - opt_filter, - lttng_dynamic_pointer_array_get_count(&exclusions), - (char **) exclusions.array.buffer.data); - if (command_ret < 0) { - switch (-command_ret) { - case LTTNG_ERR_FILTER_EXIST: - WARN("Filter on all events is already enabled" - " (channel %s, session %s)", - print_channel_name(channel_name), session_name); - warn = 1; - break; - case LTTNG_ERR_TRACE_ALREADY_STARTED: - { - const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once."; - ERR("All events: %s (channel %s, session %s, filter \'%s\')", - msg, - print_channel_name(channel_name), - session_name, opt_filter); - error = 1; - break; - } - default: - ERR("All events: %s (channel %s, session %s, filter \'%s\')", - lttng_strerror(command_ret), - command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME - ? print_raw_channel_name(channel_name) - : print_channel_name(channel_name), - session_name, opt_filter); - error = 1; - break; - } - error_holder = command_ret; - } else { - ev->filter = 1; - MSG("Filter '%s' successfully set", opt_filter); - } - } - - if (lttng_opt_mi) { - /* The wildcard * is used for kernel and ust domain to - * represent ALL. We copy * in event name to force the wildcard use - * for kernel domain - * - * Note: this is strictly for semantic and printing while in - * machine interface mode. - */ - strcpy(ev->name, "*"); - - /* If we reach here the events are enabled */ - if (!error && !warn) { - ev->enabled = 1; - } else { - ev->enabled = 0; - success = 0; - } - ret = mi_lttng_event(writer, ev, 1, handle->domain.type); - if (ret) { - ret = CMD_ERROR; - goto error; - } - - /* print exclusion */ - ret = mi_print_exclusion(&exclusions); - if (ret) { - ret = CMD_ERROR; - goto error; - } - - /* Success ? */ - ret = mi_lttng_writer_write_element_bool(writer, - mi_lttng_element_command_success, success); - if (ret) { - ret = CMD_ERROR; - goto error; - } - - /* Close event element */ - ret = mi_lttng_writer_close_element(writer); - if (ret) { - ret = CMD_ERROR; - goto error; - } - } - - goto end; - } - - /* Strip event list */ - event_name = strtok(opt_event_list, ","); - while (event_name != NULL) { + for (const auto& pattern : patterns) { /* Copy name and type of the event */ - strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN); + strncpy(ev->name, pattern.c_str(), LTTNG_SYMBOL_NAME_LEN); ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; ev->type = (lttng_event_type) opt_event_type; /* Kernel tracer action */ if (opt_kernel) { - DBG("Enabling kernel event %s for channel %s", - event_name, - print_channel_name(channel_name)); + DBG_FMT("Enabling kernel event rule: pattern=`{}`, channel_name=`{}`", + pattern, + print_channel_name(channel_name)); switch (opt_event_type) { - case LTTNG_EVENT_ALL: /* Enable tracepoints and syscalls */ + case LTTNG_EVENT_ALL: /* Enable tracepoints and syscalls */ /* If event name differs from *, select tracepoint. */ - if (strcmp(ev->name, "*")) { + if (strcmp(ev->name, "*") != 0) { ev->type = LTTNG_EVENT_TRACEPOINT; } break; @@ -857,7 +557,7 @@ static int enable_events(char *session_name) break; case CMD_ERROR: default: - ERR("Unable to parse userspace probe options"); + ERR("Unable to parse user space probe options"); break; } goto error; @@ -871,7 +571,7 @@ static int enable_events(char *session_name) } /* Ownership of the uprobe location was transferred to the event. */ - uprobe_loc = NULL; + uprobe_loc = nullptr; break; case LTTNG_EVENT_FUNCTION: ret = parse_probe_opts(ev, opt_function); @@ -891,17 +591,19 @@ static int enable_events(char *session_name) /* kernel loglevels not implemented */ ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; - } else if (opt_userspace) { /* User-space tracer action */ - DBG("Enabling UST event %s for channel %s, loglevel %s", event_name, - print_channel_name(channel_name), opt_loglevel ? : ""); + } else if (opt_userspace) { /* User-space tracer action */ + DBG_FMT("Enabling user space event rule: pattern=`{}`, channel_name=`{}`, log_level=`{}`", + pattern.c_str(), + print_channel_name(channel_name), + opt_loglevel ?: "all"); switch (opt_event_type) { - case LTTNG_EVENT_ALL: /* Default behavior is tracepoint */ + case LTTNG_EVENT_ALL: /* Default behavior is tracepoint */ /* Fall-through */ case LTTNG_EVENT_TRACEPOINT: /* Copy name and type of the event */ ev->type = LTTNG_EVENT_TRACEPOINT; - strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN); + strncpy(ev->name, pattern.c_str(), LTTNG_SYMBOL_NAME_LEN); ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; break; case LTTNG_EVENT_PROBE: @@ -909,14 +611,16 @@ static int enable_events(char *session_name) case LTTNG_EVENT_SYSCALL: case LTTNG_EVENT_USERSPACE_PROBE: default: - ERR("Event type not available for user-space tracing"); + ERR("Instrumentation point type not supported for the %s domain", + lttng_domain_type_str(dom.type)); ret = CMD_UNSUPPORTED; goto error; } if (opt_exclude) { ev->exclusion = 1; - if (opt_event_type != LTTNG_EVENT_ALL && opt_event_type != LTTNG_EVENT_TRACEPOINT) { + if (opt_event_type != LTTNG_EVENT_ALL && + opt_event_type != LTTNG_EVENT_TRACEPOINT) { ERR("Exclusion option can only be used with tracepoint events"); ret = CMD_ERROR; goto error; @@ -924,24 +628,23 @@ static int enable_events(char *session_name) /* Free previously allocated items. */ lttng_dynamic_pointer_array_reset(&exclusions); ret = create_exclusion_list_and_validate( - event_name, opt_exclude, - &exclusions); + pattern.c_str(), opt_exclude, &exclusions); if (ret) { ret = CMD_ERROR; goto error; } - warn_on_truncated_exclusion_names( - &exclusions, &warn); + warn_on_truncated_exclusion_names(&exclusions, &warn); } ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type; if (opt_loglevel) { enum lttng_loglevel loglevel; - const int name_search_ret = loglevel_name_to_value(opt_loglevel, &loglevel); + const int name_search_ret = + loglevel_name_to_value(opt_loglevel, &loglevel); if (name_search_ret == -1) { - ERR("Unknown loglevel %s", opt_loglevel); + ERR("Unknown log level `%s`", opt_loglevel); ret = -LTTNG_ERR_INVALID; goto error; } @@ -952,8 +655,9 @@ static int enable_events(char *session_name) } } else if (opt_jul || opt_log4j || opt_python) { if (opt_event_type != LTTNG_EVENT_ALL && - opt_event_type != LTTNG_EVENT_TRACEPOINT) { - ERR("Event type not supported for domain."); + opt_event_type != LTTNG_EVENT_TRACEPOINT) { + ERR("Instrumentation point type not supported for the %s domain", + lttng_domain_type_str(dom.type)); ret = CMD_UNSUPPORTED; goto error; } @@ -965,23 +669,26 @@ static int enable_events(char *session_name) if (opt_jul) { enum lttng_loglevel_jul loglevel; - name_search_ret = loglevel_jul_name_to_value(opt_loglevel, &loglevel); + name_search_ret = + loglevel_jul_name_to_value(opt_loglevel, &loglevel); ev->loglevel = (int) loglevel; } else if (opt_log4j) { enum lttng_loglevel_log4j loglevel; - name_search_ret = loglevel_log4j_name_to_value(opt_loglevel, &loglevel); + name_search_ret = loglevel_log4j_name_to_value(opt_loglevel, + &loglevel); ev->loglevel = (int) loglevel; } else { /* python domain. */ enum lttng_loglevel_python loglevel; - name_search_ret = loglevel_python_name_to_value(opt_loglevel, &loglevel); + name_search_ret = loglevel_python_name_to_value( + opt_loglevel, &loglevel); ev->loglevel = (int) loglevel; } if (name_search_ret) { - ERR("Unknown loglevel %s", opt_loglevel); + ERR("Unknown log level `%s`", opt_loglevel); ret = -LTTNG_ERR_INVALID; goto error; } @@ -995,61 +702,75 @@ static int enable_events(char *session_name) } } ev->type = LTTNG_EVENT_TRACEPOINT; - strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN); + strncpy(ev->name, pattern.c_str(), LTTNG_SYMBOL_NAME_LEN); ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; } else { abort(); } if (!opt_filter) { - char *exclusion_string; - - command_ret = lttng_enable_event_with_exclusions(handle, - ev, channel_name, - NULL, - lttng_dynamic_pointer_array_get_count(&exclusions), - (char **) exclusions.array.buffer.data); - exclusion_string = print_exclusions(&exclusions); + command_ret = lttng_enable_event_with_exclusions( + handle, + ev, + channel_name, + nullptr, + lttng_dynamic_pointer_array_get_count(&exclusions), + (char **) exclusions.array.buffer.data); + + auto exclusion_string = + lttng::make_unique_wrapper( + print_exclusions(&exclusions)); if (!exclusion_string) { PERROR("Cannot allocate exclusion_string"); error = 1; goto end; } + if (command_ret < 0) { /* Turn ret to positive value to handle the positive error code */ switch (-command_ret) { case LTTNG_ERR_KERN_EVENT_EXIST: - WARN("Kernel event %s%s already enabled (channel %s, session %s)", - event_name, - exclusion_string, - print_channel_name(channel_name), session_name); + WARN("Kernel event rule %s%s and attached to channel `%s` is already enabled (session `%s`)", + opt_enable_all ? "matching all events" : + (std::string("with pattern `") + + pattern + std::string("`")) + .c_str(), + exclusion_string.get(), + print_channel_name(channel_name), + session_name.c_str()); warn = 1; break; case LTTNG_ERR_TRACE_ALREADY_STARTED: { - const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once."; - ERR("Event %s%s: %s (channel %s, session %s)", event_name, - exclusion_string, - msg, - print_channel_name(channel_name), - session_name); + ERR("Can't enable an event in a new domain for a session that has already been started once (session `%s`)", + session_name.c_str()); error = 1; break; } case LTTNG_ERR_SDT_PROBE_SEMAPHORE: - ERR("SDT probes %s guarded by semaphores are not supported (channel %s, session %s)", - event_name, print_channel_name(channel_name), - session_name); + ERR("Failed to enable event rule with pattern `%s` and attached to channel `%s` as SDT probes guarded by semaphores are not supported (session `%s`)", + pattern.c_str(), + print_channel_name(channel_name), + session_name.c_str()); error = 1; break; default: - ERR("Event %s%s: %s (channel %s, session %s)", event_name, - exclusion_string, - lttng_strerror(command_ret), - command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME - ? print_raw_channel_name(channel_name) - : print_channel_name(channel_name), - session_name); + ERR("Failed to enable event rule %s%s and attached to channel `%s`: %s (session `%s`)", + opt_enable_all ? "matching all events" : + (std::string("with pattern `") + + pattern + std::string("`")) + .c_str(), + exclusion_string.get(), + command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ? + print_raw_channel_name(channel_name) : + print_channel_name(channel_name), + lttng_strerror(command_ret), + session_name.c_str()); + + if (opt_kernel) { + print_kernel_tracer_status_error(); + } + error = 1; break; } @@ -1058,12 +779,17 @@ static int enable_events(char *session_name) switch (dom.type) { case LTTNG_DOMAIN_KERNEL: case LTTNG_DOMAIN_UST: - MSG("%s event %s%s created in channel %s", - lttng_domain_type_str(dom.type), - event_name, - exclusion_string, - print_channel_name(channel_name)); + { + MSG("Enabled %s event rule %s%s and attached to channel `%s`", + lttng_domain_type_str(dom.type), + opt_enable_all ? "matching all events" : + (std::string("with pattern `") + + pattern + std::string("`")) + .c_str(), + exclusion_string.get(), + print_channel_name(channel_name)); break; + } case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: case LTTNG_DOMAIN_PYTHON: @@ -1071,74 +797,92 @@ static int enable_events(char *session_name) * Don't print the default channel * name for agent domains. */ - MSG("%s event %s%s enabled", - lttng_domain_type_str(dom.type), - event_name, - exclusion_string); + MSG("Enabled %s event rule %s%s", + lttng_domain_type_str(dom.type), + opt_enable_all ? "matching all events" : + (std::string("with pattern `") + + pattern + std::string("`")) + .c_str(), + exclusion_string.get()); break; default: abort(); } } - free(exclusion_string); - } - - if (opt_filter) { - char *exclusion_string; - + } else { /* Filter present */ ev->filter = 1; - command_ret = lttng_enable_event_with_exclusions(handle, ev, channel_name, - opt_filter, - lttng_dynamic_pointer_array_get_count(&exclusions), - (char **) exclusions.array.buffer.data); - exclusion_string = print_exclusions(&exclusions); + command_ret = lttng_enable_event_with_exclusions( + handle, + ev, + channel_name, + opt_filter, + lttng_dynamic_pointer_array_get_count(&exclusions), + (char **) exclusions.array.buffer.data); + + auto exclusion_string = + lttng::make_unique_wrapper( + print_exclusions(&exclusions)); if (!exclusion_string) { - PERROR("Cannot allocate exclusion_string"); + PERROR("Failed allocate exclusion string"); error = 1; goto end; } if (command_ret < 0) { switch (-command_ret) { case LTTNG_ERR_FILTER_EXIST: - WARN("Filter on event %s%s is already enabled" - " (channel %s, session %s)", - event_name, - exclusion_string, - print_channel_name(channel_name), session_name); + WARN("An event rule %s%s and filter expression `%s` is already attached to channel `%s`", + opt_enable_all ? "matching all events" : + (std::string("with pattern `") + + pattern + std::string("`")) + .c_str(), + exclusion_string.get(), + opt_filter, + print_channel_name(channel_name)); warn = 1; break; case LTTNG_ERR_TRACE_ALREADY_STARTED: { - const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once."; - ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')", ev->name, - exclusion_string, - msg, - print_channel_name(channel_name), - session_name, opt_filter); + ERR("Can't enable an event in a new domain for a session that has already been started once (session `%s`)", + session_name.c_str()); error = 1; break; } default: - ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')", ev->name, - exclusion_string, - lttng_strerror(command_ret), - command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME - ? print_raw_channel_name(channel_name) - : print_channel_name(channel_name), - session_name, opt_filter); + ERR("Failed to enable event rule %s%s, with filter expression `%s`, and attached to channel `%s`: %s (session `%s`)", + opt_enable_all ? "matching all events" : + (std::string("with pattern `") + + pattern + std::string("`")) + .c_str(), + exclusion_string.get(), + opt_filter, + command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ? + print_raw_channel_name(channel_name) : + print_channel_name(channel_name), + lttng_strerror(command_ret), + session_name.c_str()); error = 1; + + if (opt_kernel) { + print_kernel_tracer_status_error(); + } + break; } - error_holder = command_ret; + error_holder = command_ret; } else { - MSG("Event %s%s: Filter '%s' successfully set", - event_name, exclusion_string, - opt_filter); + MSG("Enabled %s event rule %s%s and filter expression `%s`", + lttng_domain_type_str(dom.type), + opt_enable_all ? "matching all events" : + (std::string("with pattern `") + pattern + + std::string("`")) + .c_str(), + + exclusion_string.get(), + opt_filter); } - free(exclusion_string); } if (lttng_opt_mi) { @@ -1149,7 +893,7 @@ static int enable_events(char *session_name) ev->enabled = 1; } - ret = mi_lttng_event(writer, ev, 1, handle->domain.type); + ret = mi_lttng_event(writer.get(), ev, 1, handle->domain.type); if (ret) { ret = CMD_ERROR; goto error; @@ -1163,23 +907,21 @@ static int enable_events(char *session_name) } /* Success ? */ - ret = mi_lttng_writer_write_element_bool(writer, - mi_lttng_element_command_success, success); + ret = mi_lttng_writer_write_element_bool( + writer.get(), mi_lttng_element_command_success, success); if (ret) { ret = CMD_ERROR; goto end; } /* Close event element */ - ret = mi_lttng_writer_close_element(writer); + ret = mi_lttng_writer_close_element(writer.get()); if (ret) { ret = CMD_ERROR; goto end; } } - /* Next event */ - event_name = strtok(NULL, ","); /* Reset warn, error and success */ success = 1; } @@ -1188,7 +930,7 @@ end: /* Close Mi */ if (lttng_opt_mi) { /* Close events element */ - ret = mi_lttng_writer_close_element(writer); + ret = mi_lttng_writer_close_element(writer.get()); if (ret) { ret = CMD_ERROR; goto error; @@ -1214,28 +956,83 @@ error: return ret; } +void _poptContextFree_deleter_func(poptContext ctx) +{ + poptFreeContext(ctx); +} + +} /* namespace */ + +int validate_exclusion_list(const char *pattern, + const struct lttng_dynamic_pointer_array *exclusions) +{ + int ret; + + /* Event name pattern must be a valid globbing pattern to allow exclusions. */ + if (!strutils_is_star_glob_pattern(pattern)) { + ERR("Event name pattern must contain wildcard characters to use exclusions"); + goto error; + } + + /* + * If the event name is a star-at-end only globbing pattern, + * then we can validate the individual exclusions. Otherwise + * all exclusions are passed to the session daemon. + */ + if (strutils_is_star_at_the_end_only_glob_pattern(pattern)) { + size_t i, num_exclusions; + + num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions); + + for (i = 0; i < num_exclusions; i++) { + const char *exclusion = + (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, + i); + + if (!strutils_is_star_glob_pattern(exclusion) || + strutils_is_star_at_the_end_only_glob_pattern(exclusion)) { + ret = check_exclusion_subsets(pattern, exclusion); + if (ret) { + goto error; + } + } + } + } + + ret = 0; + goto end; + +error: + ret = -1; + +end: + return ret; +} + /* * Add event to trace session */ int cmd_enable_events(int argc, const char **argv) { int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1; - static poptContext pc; - char *session_name = NULL; - const char *leftover = NULL; + std::string session_name; + const char *arg_event_list = nullptr; + const char *leftover = nullptr; int event_type = -1; + event_rule_patterns patterns; - pc = poptGetContext(NULL, argc, argv, long_options, 0); - poptReadDefaultConfig(pc, 0); + auto pc = lttng::make_unique_wrapper( + poptGetContext(nullptr, argc, argv, long_options, 0)); + poptReadDefaultConfig(pc.get(), 0); /* Default event type */ opt_event_type = LTTNG_EVENT_ALL; - while ((opt = poptGetNextOpt(pc)) != -1) { + while ((opt = poptGetNextOpt(pc.get())) != -1) { switch (opt) { case OPT_HELP: SHOW_HELP(); - goto end; + return CMD_SUCCESS; case OPT_TRACEPOINT: opt_event_type = LTTNG_EVENT_TRACEPOINT; break; @@ -1256,22 +1053,21 @@ int cmd_enable_events(int argc, const char **argv) break; case OPT_LOGLEVEL: opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE; - opt_loglevel = poptGetOptArg(pc); + opt_loglevel = poptGetOptArg(pc.get()); break; case OPT_LOGLEVEL_ONLY: opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE; - opt_loglevel = poptGetOptArg(pc); + opt_loglevel = poptGetOptArg(pc.get()); break; case OPT_LIST_OPTIONS: list_cmd_options(stdout, long_options); - goto end; + return CMD_SUCCESS; case OPT_FILTER: break; case OPT_EXCLUDE: break; default: - ret = CMD_UNDEFINED; - goto end; + return CMD_UNDEFINED; } /* Validate event type. Multiple event type are not supported. */ @@ -1279,118 +1075,110 @@ int cmd_enable_events(int argc, const char **argv) event_type = opt_event_type; } else { if (event_type != opt_event_type) { - ERR("Multiple event type not supported."); - ret = CMD_ERROR; - goto end; + ERR("Only one event type may be enabled at once"); + return CMD_ERROR; } } } ret = print_missing_or_multiple_domains( - opt_kernel + opt_userspace + opt_jul + opt_log4j + - opt_python, - true); + opt_kernel + opt_userspace + opt_jul + opt_log4j + opt_python, true); if (ret) { - ret = CMD_ERROR; - goto end; + return CMD_ERROR; } /* Mi check */ if (lttng_opt_mi) { - writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); + writer = mi_writer_uptr(mi_lttng_writer_create(fileno(stdout), lttng_opt_mi)); if (!writer) { - ret = -LTTNG_ERR_NOMEM; - goto end; + LTTNG_THROW_ERROR(lttng::format( + "Failed to create MI writer: format_code={}", lttng_opt_mi)); } /* Open command element */ - ret = mi_lttng_writer_command_open(writer, - mi_lttng_element_command_enable_event); + ret = mi_lttng_writer_command_open(writer.get(), + mi_lttng_element_command_enable_event); if (ret) { - ret = CMD_ERROR; - goto end; + LTTNG_THROW_ERROR(lttng::format( + "Failed to open MI command element: command_name=`{}`", + mi_lttng_element_command_enable_event)); } /* Open output element */ - ret = mi_lttng_writer_open_element(writer, - mi_lttng_element_command_output); + ret = mi_lttng_writer_open_element(writer.get(), mi_lttng_element_command_output); if (ret) { - ret = CMD_ERROR; - goto end; + LTTNG_THROW_ERROR( + lttng::format("Failed to open MI element: element_name=`{}`", + mi_lttng_element_command_output)); } } - opt_event_list = (char*) poptGetArg(pc); - if (opt_event_list == NULL && opt_enable_all == 0) { - ERR("Missing event name(s).\n"); - ret = CMD_ERROR; - goto end; - } - - leftover = poptGetArg(pc); - if (leftover) { - ERR("Unknown argument: %s", leftover); - ret = CMD_ERROR; - goto end; - } - - if (!opt_session_name) { - session_name = get_session_name(); - if (session_name == NULL) { - command_ret = CMD_ERROR; - success = 0; - goto mi_closing; + /* Close the MI command context when leaving the function, no matter the result. */ + const auto close_mi_on_exit = lttng::make_scope_exit([&success]() noexcept { + if (!lttng_opt_mi) { + return; } - } else { - session_name = opt_session_name; - } - command_ret = enable_events(session_name); - if (command_ret) { - success = 0; - goto mi_closing; - } + /* Close output element. */ + if (mi_lttng_writer_close_element(writer.get())) { + ERR_FMT("Failed to close MI output element"); + return; + } -mi_closing: - /* Mi closing */ - if (lttng_opt_mi) { - /* Close output element */ - ret = mi_lttng_writer_close_element(writer); - if (ret) { - ret = CMD_ERROR; - goto end; + if (mi_lttng_writer_write_element_bool( + writer.get(), mi_lttng_element_command_success, success)) { + ERR_FMT("Failed to write MI element: element_name=`{}`, value={}", + mi_lttng_element_command_success, + success); + return; } - ret = mi_lttng_writer_write_element_bool(writer, - mi_lttng_element_command_success, success); - if (ret) { - ret = CMD_ERROR; - goto end; + /* Command element close. */ + if (mi_lttng_writer_command_close(writer.get())) { + ERR_FMT("Failed to close MI command element"); + return; } + }); - /* Command element close */ - ret = mi_lttng_writer_command_close(writer); - if (ret) { - ret = CMD_ERROR; - goto end; + arg_event_list = poptGetArg(pc.get()); + if (arg_event_list == nullptr && opt_enable_all == 0) { + ERR("Missing event name pattern(s)"); + return CMD_ERROR; + } + + if (opt_enable_all) { + patterns.emplace_back("*"); + } else { + std::stringstream event_list_arg_stream(arg_event_list); + + for (std::string line; std::getline(event_list_arg_stream, line, ',');) { + patterns.emplace_back(std::move(line)); } } -end: - /* Mi clean-up */ - if (writer && mi_lttng_writer_destroy(writer)) { - /* Preserve original error code */ - ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL; + leftover = poptGetArg(pc.get()); + if (leftover) { + ERR("Unknown argument: %s", leftover); + return CMD_ERROR; } - if (opt_session_name == NULL) { - free(session_name); + if (!opt_session_name) { + const auto rc_file_session_name = + lttng::make_unique_wrapper(get_session_name()); + + if (!rc_file_session_name) { + return CMD_ERROR; + } + + session_name = rc_file_session_name.get(); + } else { + session_name = opt_session_name; } - /* Overwrite ret if an error occurred in enable_events */ - ret = command_ret ? command_ret : ret; + command_ret = enable_events(session_name, patterns); + if (command_ret) { + return CMD_ERROR; + } - poptFreeContext(pc); - return ret; + return CMD_SUCCESS; } -