.gitignore: ignore local vscode workspace settings file
[lttng-tools.git] / src / bin / lttng / commands / enable_events.cpp
index ef58bfa75ff0f752fc57a63c32168c1ea5faac3f..b081adeeed7f3f68d7d97f57722002091c40bef0 100644 (file)
@@ -8,6 +8,8 @@
 #define _LGPL_SOURCE
 #include <common/compat/getenv.hpp>
 #include <common/compat/string.hpp>
+#include <common/make-unique-wrapper.hpp>
+#include <common/scope-exit.hpp>
 #include <common/sessiond-comm/sessiond-comm.hpp>
 #include <common/string-utils/string-utils.hpp>
 #include <common/utils.hpp>
 #include <ctype.h>
 #include <inttypes.h>
 #include <popt.h>
+#include <sstream>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <vector>
 
 /* Mi dependancy */
 #include "../command.hpp"
 #define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
 #endif
 
-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<mi_writer, _mi_lttng_writer_deleter_func>::deleter>;
+using event_rule_patterns = std::vector<std::string>;
+
+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[] =
@@ -73,10 +94,7 @@ 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, nullptr, OPT_HELP, nullptr, nullptr },
        { "session", 's', POPT_ARG_STRING, &opt_session_name, 0, nullptr, nullptr },
@@ -109,7 +127,7 @@ static struct poptOption long_options[] = {
 /*
  * 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;
@@ -166,7 +184,7 @@ 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;
                }
@@ -184,12 +202,12 @@ end:
        return ret;
 }
 
-static const char *print_channel_name(const char *name)
+const char *print_channel_name(const char *name)
 {
        return name ?: DEFAULT_CHANNEL_NAME;
 }
 
-static const char *print_raw_channel_name(const char *name)
+const char *print_raw_channel_name(const char *name)
 {
        return name ?: "<default>";
 }
@@ -197,7 +215,7 @@ static const char *print_raw_channel_name(const char *name)
 /*
  * Mi print exlcusion list
  */
-static int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusions)
+int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusions)
 {
        int ret;
        size_t i;
@@ -210,7 +228,7 @@ static int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusio
                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;
        }
@@ -220,14 +238,14 @@ static int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusio
                        (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
 
                ret = mi_lttng_writer_write_element_string(
-                       writer, config_element_exclusion, exclusion);
+                       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;
@@ -236,7 +254,7 @@ end:
 /*
  * Return allocated string for pretty-printing exclusion names.
  */
-static char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions)
+char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions)
 {
        int length = 0;
        size_t i;
@@ -267,9 +285,9 @@ static char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusio
                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, ", ");
                }
@@ -278,11 +296,11 @@ static char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusio
        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 */
@@ -300,10 +318,9 @@ static 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,
+                       ERR("Exclusion pattern `%s` excludes all events from `%s`",
                            exclusion,
-                           event_name);
+                           pattern);
                        goto error;
                }
 
@@ -332,64 +349,17 @@ error:
 
 end:
        if (warn) {
-               WARN("Event %s: %s does not exclude any events from %s",
-                    event_name,
+               WARN("Exclusion pattern `%s` does not exclude any event from `%s`",
                     exclusion,
-                    event_name);
+                    pattern);
        }
 
        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;
-                               }
-                       }
-               }
-       }
-
-       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;
 
@@ -399,7 +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;
        }
 
@@ -413,8 +383,8 @@ 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);
@@ -434,11 +404,11 @@ 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, char *event_list)
+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 = nullptr;
+       char *channel_name = nullptr;
        struct lttng_event *ev;
        struct lttng_domain dom = {};
        struct lttng_dynamic_pointer_array exclusions;
@@ -454,7 +424,7 @@ static int enable_events(char *session_name, char *event_list)
 
        if (opt_kernel) {
                if (opt_loglevel) {
-                       WARN("Kernel loglevels are not supported.");
+                       WARN("Kernel log levels are not supported");
                }
        }
 
@@ -489,7 +459,7 @@ static int enable_events(char *session_name, char *event_list)
                case LTTNG_DOMAIN_JUL:
                case LTTNG_DOMAIN_LOG4J:
                case LTTNG_DOMAIN_PYTHON:
-                       ERR("Event name exclusions are not yet implemented for %s events",
+                       ERR("Event name exclusions are not supported for %s event rules",
                            lttng_domain_type_str(dom.type));
                        ret = CMD_ERROR;
                        goto error;
@@ -515,7 +485,7 @@ static int enable_events(char *session_name, char *event_list)
                case LTTNG_EVENT_PROBE:
                case LTTNG_EVENT_USERSPACE_PROBE:
                case LTTNG_EVENT_FUNCTION:
-                       ERR("Filter expressions are not supported for %s events",
+                       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;
@@ -527,7 +497,7 @@ static int enable_events(char *session_name, char *event_list)
 
        channel_name = opt_channel_name;
 
-       handle = lttng_create_handle(session_name, &dom);
+       handle = lttng_create_handle(session_name.c_str(), &dom);
        if (handle == nullptr) {
                ret = -1;
                goto error;
@@ -536,316 +506,29 @@ static int enable_events(char *session_name, char *event_list)
        /* 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,
-                               nullptr,
-                               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(event_list, ",");
-       while (event_name != nullptr) {
+       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 */
                                /* If event name differs from *, select tracepoint. */
-                               if (strcmp(ev->name, "*")) {
+                               if (strcmp(ev->name, "*") != 0) {
                                        ev->type = LTTNG_EVENT_TRACEPOINT;
                                }
                                break;
@@ -874,7 +557,7 @@ static int enable_events(char *session_name, char *event_list)
                                                break;
                                        case CMD_ERROR:
                                        default:
-                                               ERR("Unable to parse userspace probe options");
+                                               ERR("Unable to parse user space probe options");
                                                break;
                                        }
                                        goto error;
@@ -909,10 +592,10 @@ static int enable_events(char *session_name, char *event_list)
                        /* 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 ?: "<all>");
+                       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 */
@@ -920,7 +603,7 @@ static int enable_events(char *session_name, char *event_list)
                        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:
@@ -928,7 +611,8 @@ static int enable_events(char *session_name, char *event_list)
                        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;
                        }
@@ -944,7 +628,7 @@ static int enable_events(char *session_name, char *event_list)
                                /* 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;
@@ -960,7 +644,7 @@ static int enable_events(char *session_name, char *event_list)
                                        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;
                                }
@@ -972,7 +656,8 @@ static int enable_events(char *session_name, char *event_list)
                } 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.");
+                               ERR("Instrumentation point type not supported for the %s domain",
+                                   lttng_domain_type_str(dom.type));
                                ret = CMD_UNSUPPORTED;
                                goto error;
                        }
@@ -1003,7 +688,7 @@ static int enable_events(char *session_name, char *event_list)
                                }
 
                                if (name_search_ret) {
-                                       ERR("Unknown loglevel %s", opt_loglevel);
+                                       ERR("Unknown log level `%s`", opt_loglevel);
                                        ret = -LTTNG_ERR_INVALID;
                                        goto error;
                                }
@@ -1017,15 +702,13 @@ static int enable_events(char *session_name, char *event_list)
                                }
                        }
                        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,
@@ -1033,52 +716,61 @@ static int enable_events(char *session_name, char *event_list)
                                nullptr,
                                lttng_dynamic_pointer_array_get_count(&exclusions),
                                (char **) exclusions.array.buffer.data);
-                       exclusion_string = print_exclusions(&exclusions);
+
+                       auto exclusion_string =
+                               lttng::make_unique_wrapper<char, lttng::memory::free>(
+                                       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,
+                                       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);
+                                            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,
+                                       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);
+                                           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),
+                                       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),
-                                           session_name);
+                                           lttng_strerror(command_ret),
+                                           session_name.c_str());
+
+                                       if (opt_kernel) {
+                                               print_kernel_tracer_status_error();
+                                       }
+
                                        error = 1;
                                        break;
                                }
@@ -1087,12 +779,17 @@ static int enable_events(char *session_name, char *event_list)
                                switch (dom.type) {
                                case LTTNG_DOMAIN_KERNEL:
                                case LTTNG_DOMAIN_UST:
-                                       MSG("%s event %s%s created in channel %s",
+                               {
+                                       MSG("Enabled %s event rule %s%s and attached to channel `%s`",
                                            lttng_domain_type_str(dom.type),
-                                           event_name,
-                                           exclusion_string,
+                                           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:
@@ -1100,21 +797,19 @@ static int enable_events(char *session_name, char *event_list)
                                         * Don't print the default channel
                                         * name for agent domains.
                                         */
-                                       MSG("%s event %s%s enabled",
+                                       MSG("Enabled %s event rule %s%s",
                                            lttng_domain_type_str(dom.type),
-                                           event_name,
-                                           exclusion_string);
+                                           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;
 
@@ -1125,59 +820,69 @@ static int enable_events(char *session_name, char *event_list)
                                opt_filter,
                                lttng_dynamic_pointer_array_get_count(&exclusions),
                                (char **) exclusions.array.buffer.data);
-                       exclusion_string = print_exclusions(&exclusions);
+
+                       auto exclusion_string =
+                               lttng::make_unique_wrapper<char, lttng::memory::free>(
+                                       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),
+                                       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),
-                                           session_name,
-                                           opt_filter);
+                                           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,
+                               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) {
@@ -1188,7 +893,7 @@ static int enable_events(char *session_name, char *event_list)
                                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;
@@ -1203,22 +908,20 @@ static int enable_events(char *session_name, char *event_list)
 
                        /* Success ? */
                        ret = mi_lttng_writer_write_element_bool(
-                               writer, mi_lttng_element_command_success, success);
+                               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(nullptr, ",");
                /* Reset warn, error and success */
                success = 1;
        }
@@ -1227,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;
@@ -1253,30 +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 = nullptr;
-       char *event_list = nullptr;
+       std::string session_name;
        const char *arg_event_list = nullptr;
        const char *leftover = nullptr;
        int event_type = -1;
+       event_rule_patterns patterns;
 
-       pc = poptGetContext(nullptr, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
+       auto pc = lttng::make_unique_wrapper<poptContext_s, _poptContextFree_deleter_func>(
+               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;
@@ -1297,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. */
@@ -1320,9 +1075,8 @@ 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;
                        }
                }
        }
@@ -1330,114 +1084,101 @@ int cmd_enable_events(int argc, const char **argv)
        ret = print_missing_or_multiple_domains(
                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));
                }
        }
 
-       arg_event_list = poptGetArg(pc);
+       /* 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;
+               }
+
+               /* Close output element. */
+               if (mi_lttng_writer_close_element(writer.get())) {
+                       ERR_FMT("Failed to close MI output element");
+                       return;
+               }
+
+               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;
+               }
+
+               /* Command element close. */
+               if (mi_lttng_writer_command_close(writer.get())) {
+                       ERR_FMT("Failed to close MI command element");
+                       return;
+               }
+       });
+
+       arg_event_list = poptGetArg(pc.get());
        if (arg_event_list == nullptr && opt_enable_all == 0) {
-               ERR("Missing event name(s).");
-               ret = CMD_ERROR;
-               goto end;
+               ERR("Missing event name pattern(s)");
+               return CMD_ERROR;
        }
 
-       if (opt_enable_all == 0) {
-               event_list = strdup(arg_event_list);
-               if (event_list == nullptr) {
-                       PERROR("Failed to copy event name(s)");
-                       ret = CMD_ERROR;
-                       goto end;
+       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));
                }
        }
 
-       leftover = poptGetArg(pc);
+       leftover = poptGetArg(pc.get());
        if (leftover) {
                ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
+               return CMD_ERROR;
        }
 
        if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == nullptr) {
-                       command_ret = CMD_ERROR;
-                       success = 0;
-                       goto mi_closing;
+               const auto rc_file_session_name =
+                       lttng::make_unique_wrapper<char, lttng::memory::free>(get_session_name());
+
+               if (!rc_file_session_name) {
+                       return CMD_ERROR;
                }
+
+               session_name = rc_file_session_name.get();
        } else {
                session_name = opt_session_name;
        }
 
-       command_ret = enable_events(session_name, event_list);
+       command_ret = enable_events(session_name, patterns);
        if (command_ret) {
-               success = 0;
-               goto mi_closing;
-       }
-
-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;
-               }
-
-               ret = mi_lttng_writer_write_element_bool(
-                       writer, mi_lttng_element_command_success, success);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Command element close */
-               ret = mi_lttng_writer_command_close(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-end:
-       /* Mi clean-up */
-       if (writer && mi_lttng_writer_destroy(writer)) {
-               /* Preserve original error code */
-               ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
+               return CMD_ERROR;
        }
 
-       if (opt_session_name == nullptr) {
-               free(session_name);
-       }
-
-       free(event_list);
-
-       /* Overwrite ret if an error occurred in enable_events */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
+       return CMD_SUCCESS;
 }
This page took 0.042622 seconds and 4 git commands to generate.