]> git.lttng.org Git - lttng-tools.git/commitdiff
Maintain recording channel configuration objects in ltt_session
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Sat, 14 Sep 2024 09:36:09 +0000 (05:36 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 25 Nov 2024 19:58:09 +0000 (19:58 +0000)
Maintain the state of event rules in the ltt_session's channel
configurations. This is laying the groundwork to maintain triggers (and
ultimately, event-rules) associated with map channels.

liblttng-ctl now converts the lttng_event specifications into
event-rules which are used by the session daemon to maintain recording
channel configurations.

The objective is to share the synchronization code of
tracers (essentially, the description of enablers and channel
configuration) with the session configurations when adding support for
maps.

As of this commit, the event-rule-configurations are maintained
internally, but aren't use to synchronize the tracer configuration.

Change-Id: I6067ef31ca4b9cead55cf4c9dc2bac8dd8ca3400
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
26 files changed:
include/lttng/channel.h
include/lttng/event-rule/event-rule-internal.hpp
src/bin/lttng-sessiond/Makefile.am
src/bin/lttng-sessiond/client.cpp
src/bin/lttng-sessiond/cmd.cpp
src/bin/lttng-sessiond/cmd.hpp
src/bin/lttng-sessiond/domain.cpp [new file with mode: 0644]
src/bin/lttng-sessiond/domain.hpp [new file with mode: 0644]
src/bin/lttng-sessiond/event-rule-configuration.cpp [new file with mode: 0644]
src/bin/lttng-sessiond/event-rule-configuration.hpp [new file with mode: 0644]
src/bin/lttng-sessiond/recording-channel-configuration.cpp [new file with mode: 0644]
src/bin/lttng-sessiond/recording-channel-configuration.hpp [new file with mode: 0644]
src/bin/lttng-sessiond/session.cpp
src/bin/lttng-sessiond/session.hpp
src/common/Makefile.am
src/common/ctl/format.hpp
src/common/ctl/memory.hpp [new file with mode: 0644]
src/common/format.hpp
src/common/math.hpp [new file with mode: 0644]
src/common/string-utils/c-string-view.hpp
src/lib/lttng-ctl/Makefile.am
src/lib/lttng-ctl/channel.cpp
src/lib/lttng-ctl/event-rule-convert.cpp [new file with mode: 0644]
src/lib/lttng-ctl/event-rule-convert.hpp [new file with mode: 0644]
src/lib/lttng-ctl/lttng-ctl.cpp
tests/regression/tools/save-load/load-42-complex.lttng

index 58917ae045ccec627fe467f28708a6120b31bd97..3bad91ea5b6bfba105395406f65bf09d8c8912f3 100644 (file)
@@ -546,8 +546,8 @@ LTTNG_EXPORT extern int lttng_channel_get_lost_packet_count(struct lttng_channel
 @sa lttng_channel_set_monitor_timer_interval() --
     Sets the monitor timer period property of a channel summary.
 */
-LTTNG_EXPORT extern int lttng_channel_get_monitor_timer_interval(struct lttng_channel *channel,
-                                                                uint64_t *period);
+LTTNG_EXPORT extern int
+lttng_channel_get_monitor_timer_interval(const struct lttng_channel *channel, uint64_t *period);
 
 /*!
 @brief
@@ -623,7 +623,7 @@ channels.
 @sa lttng_channel_set_blocking_timeout() --
     Sets the blocking timeout property of a channel summary.
 */
-LTTNG_EXPORT extern int lttng_channel_get_blocking_timeout(struct lttng_channel *channel,
+LTTNG_EXPORT extern int lttng_channel_get_blocking_timeout(const struct lttng_channel *channel,
                                                           int64_t *timeout);
 
 /*!
index 1b73b06094c775a4234023b1debfa13683786ccd..c26152cf1a89c97245956beee4e845d06bf61ceb 100644 (file)
@@ -17,6 +17,7 @@
 #include <lttng/event.h>
 #include <lttng/lttng-error.h>
 
+#include <functional>
 #include <stdbool.h>
 #include <stdint.h>
 #include <sys/types.h>
@@ -52,6 +53,12 @@ using event_rule_generate_lttng_event_cb = struct lttng_event *(*) (const struct
 using event_rule_mi_serialize_cb = enum lttng_error_code (*)(const struct lttng_event_rule *,
                                                             struct mi_writer *);
 
+struct lttng_event_rule;
+
+bool lttng_event_rule_is_equal(const struct lttng_event_rule *a, const struct lttng_event_rule *b);
+
+unsigned long lttng_event_rule_hash(const struct lttng_event_rule *rule);
+
 struct lttng_event_rule {
        struct urcu_ref ref;
        enum lttng_event_rule_type type;
@@ -66,6 +73,11 @@ struct lttng_event_rule {
        event_rule_hash_cb hash;
        event_rule_generate_lttng_event_cb generate_lttng_event;
        event_rule_mi_serialize_cb mi_serialize;
+
+       bool operator==(const lttng_event_rule& other) const
+       {
+               return lttng_event_rule_is_equal(this, &other);
+       }
 };
 
 struct lttng_event_rule_comm {
@@ -74,6 +86,28 @@ struct lttng_event_rule_comm {
        char payload[];
 };
 
+/* Specialize std::hash for lttng_event_rule (by reference) */
+namespace std {
+template <>
+struct hash<std::reference_wrapper<const lttng_event_rule>> {
+       std::size_t
+       operator()(const std::reference_wrapper<const lttng_event_rule> rule) const noexcept
+       {
+               return lttng_event_rule_hash(&rule.get());
+       }
+};
+} /* namespace std */
+
+/* Implement equality comparison for std::reference_wrapper of lttng_event_rule */
+struct lttng_event_rule_ref_equal {
+       bool operator()(const std::reference_wrapper<const lttng_event_rule> lhs,
+                       const std::reference_wrapper<const lttng_event_rule> rhs) const
+       {
+               /* Use the operator== defined for lttng_event_rule. */
+               return lhs.get() == rhs.get();
+       }
+};
+
 void lttng_event_rule_init(struct lttng_event_rule *event_rule, enum lttng_event_rule_type type);
 
 bool lttng_event_rule_validate(const struct lttng_event_rule *event_rule);
@@ -84,8 +118,6 @@ ssize_t lttng_event_rule_create_from_payload(struct lttng_payload_view *payload,
 int lttng_event_rule_serialize(const struct lttng_event_rule *event_rule,
                               struct lttng_payload *payload);
 
-bool lttng_event_rule_is_equal(const struct lttng_event_rule *a, const struct lttng_event_rule *b);
-
 bool lttng_event_rule_get(struct lttng_event_rule *rule);
 
 void lttng_event_rule_put(struct lttng_event_rule *rule);
@@ -119,8 +151,6 @@ lttng_event_rule_generate_exclusions(const struct lttng_event_rule *rule,
 
 const char *lttng_event_rule_type_str(enum lttng_event_rule_type type);
 
-unsigned long lttng_event_rule_hash(const struct lttng_event_rule *rule);
-
 /*
  * This is a compatibility helper allowing us to generate a sessiond-side (not
  * communication) `struct lttng_event` object from an event rule.
index c6ccbe5e5ad9dae097358c7727734fdd9f40526f..295ad02f33c9ebdca387c03a00362e9a09d7fc34 100644 (file)
@@ -65,7 +65,10 @@ liblttng_sessiond_common_la_SOURCES = utils.cpp utils.hpp \
                        trace-class.hpp trace-class.cpp \
                        consumer-destination-type.hpp \
                        consumer-output.hpp \
-                       snapshot-output.hpp
+                       snapshot-output.hpp \
+                       recording-channel-configuration.hpp recording-channel-configuration.cpp \
+                       event-rule-configuration.hpp event-rule-configuration.cpp \
+                       domain.hpp domain.cpp
 
 if HAVE_LIBLTTNG_UST_CTL
 liblttng_sessiond_common_la_SOURCES += trace-ust.cpp ust-registry.cpp ust-app.cpp \
index 536e2671466f442e2c690035c323dda8721e1fa4..f26480b9130c0d162b6baf6431d98aaf71dc43cd 100644 (file)
@@ -22,6 +22,8 @@
 #include <common/buffer-view.hpp>
 #include <common/compat/getenv.hpp>
 #include <common/compat/socket.hpp>
+#include <common/ctl/format.hpp>
+#include <common/ctl/memory.hpp>
 #include <common/dynamic-array.hpp>
 #include <common/dynamic-buffer.hpp>
 #include <common/exception.hpp>
@@ -37,6 +39,7 @@
 
 #include <lttng/error-query-internal.hpp>
 #include <lttng/event-internal.hpp>
+#include <lttng/event-rule/event-rule-internal.hpp>
 #include <lttng/lttng.h>
 #include <lttng/session-descriptor-internal.hpp>
 #include <lttng/session-internal.hpp>
@@ -744,7 +747,8 @@ static enum lttng_error_code receive_lttng_event(struct command_ctx *cmd_ctx,
                                                 struct lttng_event **out_event,
                                                 char **out_filter_expression,
                                                 struct lttng_bytecode **out_bytecode,
-                                                struct lttng_event_exclusion **out_exclusion)
+                                                struct lttng_event_exclusion **out_exclusion,
+                                                lttng::event_rule_uptr& event_rule)
 {
        int ret;
        size_t event_len;
@@ -803,7 +807,7 @@ static enum lttng_error_code receive_lttng_event(struct command_ctx *cmd_ctx,
        /* Deserialize event. */
        {
                ssize_t len;
-               struct lttng_payload_view event_view =
+               lttng_payload_view event_view =
                        lttng_payload_view_from_payload(&event_payload, 0, -1);
 
                len = lttng_event_create_from_payload(&event_view,
@@ -818,13 +822,29 @@ static enum lttng_error_code receive_lttng_event(struct command_ctx *cmd_ctx,
                        goto end;
                }
 
-               if (len != event_len) {
-                       ERR("Userspace probe location from the received buffer is not the advertised length: header length = %zu" PRIu32
-                           ", payload length = %zd",
-                           event_len,
-                           len);
-                       ret_code = LTTNG_ERR_INVALID_PROTOCOL;
-                       goto end;
+               lttng_payload_view event_rule_view =
+                       lttng_payload_view_from_payload(&event_payload, len, -1);
+
+               /*
+                * The disable event command, when issued with LTTNG_EVENT_ALL,
+                * does not provide an event rule.
+                *
+                * The semantics of LTTNG_EVENT_ALL vary between enable and disable
+                * event commands:
+                *   - enable: means enable all tracepoints and syscalls (if kernel domain).
+                *   - disable: disable any enabled event regardless of instrumentation type.
+                */
+               if (event_rule_view.buffer.size > 0) {
+                       lttng_event_rule *raw_event_rule;
+                       ret = lttng_event_rule_create_from_payload(&event_rule_view,
+                                                                  &raw_event_rule);
+                       if (ret < 0) {
+                               ERR("Failed to create an event rule from the received buffer");
+                               ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+                               goto end;
+                       }
+
+                       event_rule.reset(raw_event_rule);
                }
        }
 
@@ -1439,9 +1459,21 @@ skip_domain:
        }
        case LTTCOMM_SESSIOND_COMMAND_DISABLE_CHANNEL:
        {
-               ret = cmd_disable_channel(*target_session,
-                                         cmd_ctx->lsm.domain.type,
-                                         cmd_ctx->lsm.u.disable.channel_name);
+               try {
+                       ret = cmd_disable_channel(*target_session,
+                                                 cmd_ctx->lsm.domain.type,
+                                                 cmd_ctx->lsm.u.disable.channel_name);
+               } catch (const std::out_of_range& oor_ex) {
+                       const auto channel_name = cmd_ctx->lsm.u.disable.channel_name;
+                       const auto domain_type = cmd_ctx->lsm.domain.type;
+
+                       ERR_FMT("Failed to disable channel: session_name=`{}`, channel_name=`{}`, domain={}",
+                               (*target_session)->name,
+                               channel_name,
+                               domain_type);
+                       ret = LTTNG_ERR_CHAN_NOT_FOUND;
+               }
+
                break;
        }
        case LTTCOMM_SESSIOND_COMMAND_ENABLE_CHANNEL:
@@ -1629,13 +1661,15 @@ skip_domain:
                char *filter_expression;
                struct lttng_event_exclusion *exclusions;
                struct lttng_bytecode *bytecode;
+               lttng::event_rule_uptr event_rule;
                const enum lttng_error_code ret_code = receive_lttng_event(cmd_ctx,
                                                                           *sock,
                                                                           sock_error,
                                                                           &event,
                                                                           &filter_expression,
                                                                           &bytecode,
-                                                                          &exclusions);
+                                                                          &exclusions,
+                                                                          event_rule);
 
                if (ret_code != LTTNG_OK) {
                        ret = (int) ret_code;
@@ -1653,13 +1687,15 @@ skip_domain:
                                         filter_expression,
                                         exclusions,
                                         bytecode,
-                                        the_kernel_poll_pipe[1]) :
+                                        the_kernel_poll_pipe[1],
+                                        std::move(event_rule)) :
                        cmd_disable_event(cmd_ctx,
                                          *target_session,
                                          event,
                                          filter_expression,
                                          bytecode,
-                                         exclusions);
+                                         exclusions,
+                                         std::move(event_rule));
                lttng_event_destroy(event);
                break;
        }
@@ -2596,6 +2632,9 @@ static void *thread_manage_clients(void *data)
                } catch (const lttng::sessiond::exceptions::session_not_found_error& ex) {
                        log_nested_exceptions(ex);
                        ret = LTTNG_ERR_SESS_NOT_FOUND;
+               } catch (const lttng::sessiond::exceptions::channel_not_found_error& ex) {
+                       log_nested_exceptions(ex);
+                       ret = LTTNG_ERR_CHAN_NOT_FOUND;
                } catch (const lttng::runtime_error& ex) {
                        log_nested_exceptions(ex);
                        ret = LTTNG_ERR_UNK;
index 76abcd65d02704891f57f2794d3f317df4f17f59..3906b30c6fb17cc1f39052b12e925946253e72f4 100644 (file)
@@ -23,6 +23,7 @@
 #include "lttng-syscall.hpp"
 #include "notification-thread-commands.hpp"
 #include "notification-thread.hpp"
+#include "recording-channel-configuration.hpp"
 #include "rotation-thread.hpp"
 #include "session.hpp"
 #include "timer.hpp"
 #include <common/buffer-view.hpp>
 #include <common/common.hpp>
 #include <common/compat/string.hpp>
+#include <common/ctl/format.hpp>
 #include <common/defaults.hpp>
 #include <common/dynamic-buffer.hpp>
+#include <common/exception.hpp>
 #include <common/kernel-ctl/kernel-ctl.hpp>
+#include <common/make-unique-wrapper.hpp>
+#include <common/math.hpp>
 #include <common/payload-view.hpp>
 #include <common/payload.hpp>
 #include <common/relayd/relayd.hpp>
+#include <common/scope-exit.hpp>
 #include <common/sessiond-comm/sessiond-comm.hpp>
 #include <common/string-utils/string-utils.hpp>
 #include <common/trace-chunk.hpp>
@@ -76,6 +82,7 @@
 /* Sleep for 100ms between each check for the shm path's deletion. */
 #define SESSION_DESTROY_SHM_PATH_CHECK_DELAY_US 100000
 
+namespace ls = lttng::sessiond;
 namespace lsu = lttng::sessiond::ust;
 
 static enum lttng_error_code wait_on_path(void *path);
@@ -124,10 +131,11 @@ static int cmd_enable_event_internal(ltt_session::locked_ref& session,
                                     char *filter_expression,
                                     struct lttng_bytecode *filter,
                                     struct lttng_event_exclusion *exclusion,
-                                    int wpipe);
+                                    int wpipe,
+                                    lttng::event_rule_uptr event_rule);
 static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref& session,
                                                         const struct lttng_domain *domain,
-                                                        const struct lttng_channel *_attr,
+                                                        const struct lttng_channel& channel_attr,
                                                         int wpipe);
 
 /*
@@ -1218,6 +1226,31 @@ error:
        return ret;
 }
 
+namespace {
+lttng::sessiond::domain_class
+get_domain_class_from_ctl_domain_type(enum lttng_domain_type domain_type)
+{
+       switch (domain_type) {
+       case LTTNG_DOMAIN_KERNEL:
+               return lttng::sessiond::domain_class::KERNEL_SPACE;
+       case LTTNG_DOMAIN_UST:
+               return lttng::sessiond::domain_class::USER_SPACE;
+       case LTTNG_DOMAIN_JUL:
+               return lttng::sessiond::domain_class::JAVA_UTIL_LOGGING;
+       case LTTNG_DOMAIN_LOG4J:
+               return lttng::sessiond::domain_class::LOG4J;
+       case LTTNG_DOMAIN_PYTHON:
+               return lttng::sessiond::domain_class::PYTHON_LOGGING;
+       case LTTNG_DOMAIN_LOG4J2:
+               return lttng::sessiond::domain_class::LOG4J2;
+       default:
+               LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+                       "No suitable conversion exists from lttng_domain_type enum to lttng::sessiond::domain_class: domain={}",
+                       domain_type));
+       }
+}
+} /* namespace */
+
 /*
  * Command LTTNG_DISABLE_CHANNEL processed by the client thread.
  */
@@ -1225,19 +1258,21 @@ int cmd_disable_channel(const ltt_session::locked_ref& session,
                        enum lttng_domain_type domain,
                        char *channel_name)
 {
-       int ret;
-       struct ltt_ust_session *usess;
+       ls::domain& target_domain =
+               session->get_domain(get_domain_class_from_ctl_domain_type(domain));
 
-       usess = session->ust_session;
+       /* Throws if not found. */
+       auto& channel_config = target_domain.get_channel(channel_name);
 
        const lttng::urcu::read_lock_guard read_lock;
 
        switch (domain) {
        case LTTNG_DOMAIN_KERNEL:
        {
-               ret = channel_kernel_disable(session->kernel_session, channel_name);
-               if (ret != LTTNG_OK) {
-                       goto error;
+               const auto disable_ret =
+                       channel_kernel_disable(session->kernel_session, channel_name);
+               if (disable_ret != LTTNG_OK) {
+                       return disable_ret;
                }
 
                kernel_wait_quiescent();
@@ -1245,32 +1280,28 @@ int cmd_disable_channel(const ltt_session::locked_ref& session,
        }
        case LTTNG_DOMAIN_UST:
        {
-               struct ltt_ust_channel *uchan;
-               struct lttng_ht *chan_ht;
-
-               chan_ht = usess->domain_global.channels;
+               const auto usess = session->ust_session;
+               const auto chan_ht = usess->domain_global.channels;
+               const auto uchan = trace_ust_find_channel_by_name(chan_ht, channel_name);
 
-               uchan = trace_ust_find_channel_by_name(chan_ht, channel_name);
                if (uchan == nullptr) {
-                       ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
-                       goto error;
+                       return LTTNG_ERR_UST_CHAN_NOT_FOUND;
                }
 
-               ret = channel_ust_disable(usess, uchan);
-               if (ret != LTTNG_OK) {
-                       goto error;
+               const auto disable_ret = channel_ust_disable(usess, uchan);
+               if (disable_ret != LTTNG_OK) {
+                       return disable_ret;
                }
+
                break;
        }
        default:
-               ret = LTTNG_ERR_UNKNOWN_DOMAIN;
-               goto error;
+               return LTTNG_ERR_UNKNOWN_DOMAIN;
        }
 
-       ret = LTTNG_OK;
+       channel_config.disable();
 
-error:
-       return ret;
+       return LTTNG_OK;
 }
 
 /*
@@ -1280,80 +1311,86 @@ error:
  */
 int cmd_enable_channel(command_ctx *cmd_ctx, ltt_session::locked_ref& session, int sock, int wpipe)
 {
-       int ret;
-       size_t channel_len;
-       ssize_t sock_recv_len;
-       struct lttng_channel *channel = nullptr;
-       struct lttng_buffer_view view;
-       struct lttng_dynamic_buffer channel_buffer;
        const struct lttng_domain command_domain = cmd_ctx->lsm.domain;
 
+       if (command_domain.type == LTTNG_DOMAIN_NONE) {
+               return LTTNG_ERR_INVALID;
+       }
+
+       /* Free buffer contents on function exit using a scope_exit. */
+       lttng_dynamic_buffer channel_buffer;
        lttng_dynamic_buffer_init(&channel_buffer);
-       channel_len = (size_t) cmd_ctx->lsm.u.channel.length;
-       ret = lttng_dynamic_buffer_set_size(&channel_buffer, channel_len);
-       if (ret) {
-               ret = LTTNG_ERR_NOMEM;
-               goto end;
+       auto destroy_buffer = lttng::make_scope_exit(
+               [&channel_buffer]() noexcept { lttng_dynamic_buffer_reset(&channel_buffer); });
+
+       const size_t channel_len = (size_t) cmd_ctx->lsm.u.channel.length;
+
+       const int buffer_alloc_ret = lttng_dynamic_buffer_set_size(&channel_buffer, channel_len);
+       if (buffer_alloc_ret) {
+               return LTTNG_ERR_NOMEM;
        }
 
-       sock_recv_len = lttcomm_recv_unix_sock(sock, channel_buffer.data, channel_len);
+       const auto sock_recv_len = lttcomm_recv_unix_sock(sock, channel_buffer.data, channel_len);
        if (sock_recv_len < 0 || sock_recv_len != channel_len) {
                ERR("Failed to receive \"enable channel\" command payload");
-               ret = LTTNG_ERR_INVALID;
-               goto end;
+               return LTTNG_ERR_INVALID;
        }
 
-       view = lttng_buffer_view_from_dynamic_buffer(&channel_buffer, 0, channel_len);
+       auto view = lttng_buffer_view_from_dynamic_buffer(&channel_buffer, 0, channel_len);
        if (!lttng_buffer_view_is_valid(&view)) {
-               ret = LTTNG_ERR_INVALID;
-               goto end;
+               /* lttng_buffer_view_from_dynamic_buffer already logs on error. */
+               return LTTNG_ERR_INVALID;
        }
 
-       if (lttng_channel_create_from_buffer(&view, &channel) != channel_len) {
-               ERR("Invalid channel payload received in \"enable channel\" command");
-               ret = LTTNG_ERR_INVALID;
-               goto end;
-       }
+       auto channel = lttng::make_unique_wrapper<lttng_channel,
+                                                 lttng_channel_destroy>([&view, channel_len]() {
+               lttng_channel *raw_channel = nullptr;
+
+               if (lttng_channel_create_from_buffer(&view, &raw_channel) != channel_len) {
+                       LTTNG_THROW_PROTOCOL_ERROR(
+                               "Invalid channel payload received in \"enable channel\" command");
+               }
 
-       ret = cmd_enable_channel_internal(session, &command_domain, channel, wpipe);
+               return raw_channel;
+       }());
 
-end:
-       lttng_dynamic_buffer_reset(&channel_buffer);
-       lttng_channel_destroy(channel);
-       return ret;
+       const auto cmd_ret = cmd_enable_channel_internal(session, &command_domain, *channel, wpipe);
+       if (cmd_ret != LTTNG_OK) {
+               return cmd_ret;
+       }
+
+       return LTTNG_OK;
 }
 
 static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref& session,
                                                         const struct lttng_domain *domain,
-                                                        const struct lttng_channel *_attr,
+                                                        const struct lttng_channel& channel_attr,
                                                         int wpipe)
 {
        enum lttng_error_code ret_code;
        struct ltt_ust_session *usess = session->ust_session;
        struct lttng_ht *chan_ht;
        size_t len;
-       struct lttng_channel *attr = nullptr;
 
-       LTTNG_ASSERT(_attr);
        LTTNG_ASSERT(domain);
 
        const lttng::urcu::read_lock_guard read_lock;
 
-       attr = lttng_channel_copy(_attr);
-       if (!attr) {
-               ret_code = LTTNG_ERR_NOMEM;
-               goto end;
+       auto new_channel_attr = lttng::make_unique_wrapper<lttng_channel, lttng_channel_destroy>(
+               lttng_channel_copy(&channel_attr));
+       if (!new_channel_attr) {
+               return LTTNG_ERR_NOMEM;
        }
 
-       len = lttng_strnlen(attr->name, sizeof(attr->name));
+       len = lttng_strnlen(new_channel_attr->name, sizeof(new_channel_attr->name));
 
        /* Validate channel name */
-       if (attr->name[0] == '.' || memchr(attr->name, '/', len) != nullptr) {
-               ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
-               goto end;
+       if (new_channel_attr->name[0] == '.' ||
+           memchr(new_channel_attr->name, '/', len) != nullptr) {
+               return LTTNG_ERR_INVALID_CHANNEL_NAME;
        }
 
-       DBG("Enabling channel %s for session %s", attr->name, session->name);
+       DBG("Enabling channel %s for session %s", new_channel_attr->name, session->name);
 
        /*
         * If the session is a live session, remove the switch timer, the
@@ -1361,8 +1398,8 @@ static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref
         * beacons for inactive streams.
         */
        if (session->live_timer > 0) {
-               attr->attr.live_timer_interval = session->live_timer;
-               attr->attr.switch_timer_interval = 0;
+               new_channel_attr->attr.live_timer_interval = session->live_timer;
+               new_channel_attr->attr.switch_timer_interval = 0;
        }
 
        /* Check for feature support */
@@ -1374,10 +1411,11 @@ static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref
                        WARN("Kernel tracer does not support buffer monitoring. "
                             "Setting the monitor interval timer to 0 "
                             "(disabled) for channel '%s' of session '%s'",
-                            attr->name,
+                            new_channel_attr->name,
                             session->name);
-                       lttng_channel_set_monitor_timer_interval(attr, 0);
+                       lttng_channel_set_monitor_timer_interval(new_channel_attr.get(), 0);
                }
+
                break;
        }
        case LTTNG_DOMAIN_UST:
@@ -1388,13 +1426,12 @@ static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref
        case LTTNG_DOMAIN_PYTHON:
                if (!agent_tracing_is_enabled()) {
                        DBG("Attempted to enable a channel in an agent domain but the agent thread is not running");
-                       ret_code = LTTNG_ERR_AGENT_TRACING_DISABLED;
-                       goto error;
+                       return LTTNG_ERR_AGENT_TRACING_DISABLED;
                }
+
                break;
        default:
-               ret_code = LTTNG_ERR_UNKNOWN_DOMAIN;
-               goto error;
+               return LTTNG_ERR_UNKNOWN_DOMAIN;
        }
 
        switch (domain->type) {
@@ -1402,23 +1439,25 @@ static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref
        {
                struct ltt_kernel_channel *kchan;
 
-               kchan = trace_kernel_get_channel_by_name(attr->name, session->kernel_session);
+               kchan = trace_kernel_get_channel_by_name(new_channel_attr->name,
+                                                        session->kernel_session);
                if (kchan == nullptr) {
                        /*
                         * Don't try to create a channel if the session has been started at
                         * some point in time before. The tracer does not allow it.
                         */
                        if (session->has_been_started) {
-                               ret_code = LTTNG_ERR_TRACE_ALREADY_STARTED;
-                               goto error;
+                               return LTTNG_ERR_TRACE_ALREADY_STARTED;
                        }
 
                        if (session->snapshot.nb_output > 0 || session->snapshot_mode) {
                                /* Enforce mmap output for snapshot sessions. */
-                               attr->attr.output = LTTNG_EVENT_MMAP;
+                               new_channel_attr->attr.output = LTTNG_EVENT_MMAP;
                        }
-                       ret_code = channel_kernel_create(session->kernel_session, attr, wpipe);
-                       if (attr->name[0] != '\0') {
+
+                       ret_code = channel_kernel_create(
+                               session->kernel_session, new_channel_attr.get(), wpipe);
+                       if (new_channel_attr->name[0] != '\0') {
                                session->kernel_session->has_non_default_channel = 1;
                        }
                } else {
@@ -1426,7 +1465,7 @@ static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref
                }
 
                if (ret_code != LTTNG_OK) {
-                       goto error;
+                       return ret_code;
                }
 
                kernel_wait_quiescent();
@@ -1449,68 +1488,221 @@ static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref
                 * adhered to.
                 */
                if (domain->type == LTTNG_DOMAIN_JUL) {
-                       if (strncmp(attr->name,
+                       if (strncmp(new_channel_attr->name,
                                    DEFAULT_JUL_CHANNEL_NAME,
                                    LTTNG_SYMBOL_NAME_LEN - 1) != 0) {
-                               ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
-                               goto error;
+                               return LTTNG_ERR_INVALID_CHANNEL_NAME;
                        }
                } else if (domain->type == LTTNG_DOMAIN_LOG4J) {
-                       if (strncmp(attr->name,
+                       if (strncmp(new_channel_attr->name,
                                    DEFAULT_LOG4J_CHANNEL_NAME,
                                    LTTNG_SYMBOL_NAME_LEN - 1) != 0) {
-                               ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
-                               goto error;
+                               return LTTNG_ERR_INVALID_CHANNEL_NAME;
                        }
                } else if (domain->type == LTTNG_DOMAIN_LOG4J2) {
-                       if (strncmp(attr->name,
+                       if (strncmp(new_channel_attr->name,
                                    DEFAULT_LOG4J2_CHANNEL_NAME,
                                    LTTNG_SYMBOL_NAME_LEN - 1) != 0) {
-                               ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
-                               goto error;
+                               return LTTNG_ERR_INVALID_CHANNEL_NAME;
                        }
                } else if (domain->type == LTTNG_DOMAIN_PYTHON) {
-                       if (strncmp(attr->name,
+                       if (strncmp(new_channel_attr->name,
                                    DEFAULT_PYTHON_CHANNEL_NAME,
                                    LTTNG_SYMBOL_NAME_LEN - 1) != 0) {
-                               ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
-                               goto error;
+                               return LTTNG_ERR_INVALID_CHANNEL_NAME;
                        }
                }
 
                chan_ht = usess->domain_global.channels;
 
-               uchan = trace_ust_find_channel_by_name(chan_ht, attr->name);
+               uchan = trace_ust_find_channel_by_name(chan_ht, new_channel_attr->name);
                if (uchan == nullptr) {
                        /*
                         * Don't try to create a channel if the session has been started at
                         * some point in time before. The tracer does not allow it.
                         */
                        if (session->has_been_started) {
-                               ret_code = LTTNG_ERR_TRACE_ALREADY_STARTED;
-                               goto error;
+                               return LTTNG_ERR_TRACE_ALREADY_STARTED;
                        }
 
-                       ret_code = channel_ust_create(usess, attr, domain->buf_type);
-                       if (attr->name[0] != '\0') {
+                       ret_code =
+                               channel_ust_create(usess, new_channel_attr.get(), domain->buf_type);
+                       if (new_channel_attr->name[0] != '\0') {
                                usess->has_non_default_channel = 1;
                        }
                } else {
                        ret_code = channel_ust_enable(usess, uchan);
                }
+
                break;
        }
        default:
-               ret_code = LTTNG_ERR_UNKNOWN_DOMAIN;
-               goto error;
+               return LTTNG_ERR_UNKNOWN_DOMAIN;
        }
 
-       if (ret_code == LTTNG_OK && attr->attr.output != LTTNG_EVENT_MMAP) {
+       if (ret_code == LTTNG_OK && new_channel_attr->attr.output != LTTNG_EVENT_MMAP) {
                session->has_non_mmap_channel = true;
        }
-error:
-end:
-       lttng_channel_destroy(attr);
+
+       const auto subbuffer_count = channel_attr.attr.num_subbuf;
+
+       const auto switch_timer_period_us = [&channel_attr]() {
+               return channel_attr.attr.switch_timer_interval > 0 ?
+                       decltype(ls::recording_channel_configuration::switch_timer_period_us)(
+                               channel_attr.attr.switch_timer_interval) :
+                       nonstd::nullopt;
+       }();
+
+       const auto read_timer_period_us = [&channel_attr]() {
+               return channel_attr.attr.read_timer_interval > 0 ?
+                       decltype(ls::recording_channel_configuration::read_timer_period_us)(
+                               channel_attr.attr.read_timer_interval) :
+                       nonstd::nullopt;
+       }();
+
+       const auto live_timer_period_us = [&channel_attr]() {
+               return channel_attr.attr.live_timer_interval > 0 ?
+                       decltype(ls::recording_channel_configuration::live_timer_period_us)(
+                               channel_attr.attr.live_timer_interval) :
+                       nonstd::nullopt;
+       }();
+
+       const auto monitor_timer_period_us = [&channel_attr]() {
+               std::uint64_t period;
+               const int ret = lttng_channel_get_monitor_timer_interval(&channel_attr, &period);
+
+               if (ret) {
+                       LTTNG_THROW_ERROR(fmt::format(
+                               "Failed to retrieve monitor timer period from channel: channel_name=`{}`",
+                               channel_attr.name));
+               }
+
+               return period > 0 ?
+                       decltype(ls::recording_channel_configuration::monitor_timer_period_us)(
+                               period) :
+                       nonstd::nullopt;
+       }();
+
+       auto blocking_policy = [&channel_attr]() {
+               std::int64_t timeout_us;
+               const int ret = lttng_channel_get_blocking_timeout(&channel_attr, &timeout_us);
+
+               if (ret) {
+                       LTTNG_THROW_ERROR(fmt::format(
+                               "Failed to retrieve blocking timeout from channel: channel_name=`{}`",
+                               channel_attr.name));
+               }
+
+               switch (timeout_us) {
+               case 0:
+                       return ls::recording_channel_configuration::consumption_blocking_policy(
+                               ls::recording_channel_configuration::consumption_blocking_policy::
+                                       mode::NONE);
+               case -1:
+                       return ls::recording_channel_configuration::consumption_blocking_policy(
+                               ls::recording_channel_configuration::consumption_blocking_policy::
+                                       mode::UNBOUNDED);
+               default:
+                       if (timeout_us < 0) {
+                               /*Negative, but not -1. */
+                               LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+                                       "Invalid buffer consumption blocking policy timeout value: timeout_us={}",
+                                       timeout_us));
+                       }
+
+                       return ls::recording_channel_configuration::consumption_blocking_policy(
+                               ls::recording_channel_configuration::consumption_blocking_policy::
+                                       mode::TIMED,
+                               timeout_us);
+               }
+       }();
+
+       ls::domain& target_domain =
+               session->get_domain(get_domain_class_from_ctl_domain_type(domain->type));
+
+       /* Extract all channel properties needed to initialize the channel. */
+       auto name = std::string(channel_attr.name[0] ? channel_attr.name : DEFAULT_CHANNEL_NAME);
+       const auto is_enabled = !!channel_attr.enabled;
+       const auto buffer_full_policy = [&session](int overwrite_value) {
+               switch (overwrite_value) {
+               case -1:
+                       /* Session default. */
+                       return session->snapshot_mode ?
+                               ls::recording_channel_configuration::buffer_full_policy_t::
+                                       OVERWRITE_OLDEST_PACKET :
+                               ls::recording_channel_configuration::buffer_full_policy_t::
+                                       DISCARD_EVENT;
+               case 0:
+                       return ls::recording_channel_configuration::buffer_full_policy_t::
+                               DISCARD_EVENT;
+               case 1:
+                       return ls::recording_channel_configuration::buffer_full_policy_t::
+                               OVERWRITE_OLDEST_PACKET;
+               default:
+                       LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+                               "Invalid channel overwrite property value received: value={}",
+                               overwrite_value));
+               }
+       }(channel_attr.attr.overwrite);
+       const auto trace_file_size_limit_bytes = channel_attr.attr.tracefile_size ?
+               decltype(ls::recording_channel_configuration::trace_file_size_limit_bytes)(
+                       channel_attr.attr.tracefile_size) :
+               nonstd::nullopt;
+
+       const auto trace_file_count_limit = channel_attr.attr.tracefile_count ?
+               decltype(ls::recording_channel_configuration::trace_file_count_limit)(
+                       channel_attr.attr.tracefile_count) :
+               nonstd::nullopt;
+
+       /* Validate consumption backend (mmap or splice). */
+       if (target_domain.domain_class_ != ls::domain_class::KERNEL_SPACE &&
+           channel_attr.attr.output != LTTNG_EVENT_MMAP) {
+               LTTNG_THROW_UNSUPPORTED_ERROR(fmt::format(
+                       "Buffer consumption back-end is unsupported by this domain: domain={}, backend=SPLICE",
+                       target_domain.domain_class_));
+       }
+
+       const auto buffer_consumption_backend = channel_attr.attr.output == LTTNG_EVENT_MMAP ?
+               ls::recording_channel_configuration::buffer_consumption_backend_t::MMAP :
+               ls::recording_channel_configuration::buffer_consumption_backend_t::SPLICE;
+
+       /* Validate sub-buffer size. */
+       if (!lttng::math::is_power_of_two(channel_attr.attr.subbuf_size) ||
+           channel_attr.attr.subbuf_size < the_page_size) {
+               LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+                       "Invalid subbuffer size (must be a power of two and equal or larger than the page size): subbuffer_size={}, page_size={}",
+                       channel_attr.attr.subbuf_size,
+                       the_page_size));
+       }
+
+       const auto subbuffer_size_bytes = channel_attr.attr.subbuf_size;
+
+       /* Validate sub-buffer count. */
+       if (!lttng::math::is_power_of_two(channel_attr.attr.num_subbuf)) {
+               LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+                       "Invalid subbuffer count (must be a power of two): subbuffer_count={}",
+                       channel_attr.attr.num_subbuf));
+       }
+
+       try {
+               target_domain.get_channel(name).enable();
+       } catch (const lttng::sessiond::exceptions::channel_not_found_error& ex) {
+               /* Channel doesn't exist, create it. */
+               target_domain.add_channel(is_enabled,
+                                         std::move(name),
+                                         buffer_full_policy,
+                                         buffer_consumption_backend,
+                                         subbuffer_size_bytes,
+                                         subbuffer_count,
+                                         switch_timer_period_us,
+                                         read_timer_period_us,
+                                         live_timer_period_us,
+                                         monitor_timer_period_us,
+                                         std::move(blocking_policy),
+                                         trace_file_size_limit_bytes,
+                                         trace_file_count_limit);
+       }
+
        return ret_code;
 }
 
@@ -1715,48 +1907,135 @@ end:
        return ret_code;
 }
 
+namespace {
+/* An unset value means 'match all'. */
+nonstd::optional<lttng::c_string_view>
+get_event_rule_pattern_or_name(const lttng_event_rule& event_rule)
+{
+       lttng_event_rule_status status;
+       const char *pattern_or_name;
+
+       switch (lttng_event_rule_get_type(&event_rule)) {
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
+               status = lttng_event_rule_kernel_syscall_get_name_pattern(&event_rule,
+                                                                         &pattern_or_name);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
+               status = lttng_event_rule_kernel_kprobe_get_event_name(&event_rule,
+                                                                      &pattern_or_name);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
+               status = lttng_event_rule_kernel_tracepoint_get_name_pattern(&event_rule,
+                                                                            &pattern_or_name);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
+               status = lttng_event_rule_kernel_uprobe_get_event_name(&event_rule,
+                                                                      &pattern_or_name);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+               status = lttng_event_rule_user_tracepoint_get_name_pattern(&event_rule,
+                                                                          &pattern_or_name);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+               status = lttng_event_rule_jul_logging_get_name_pattern(&event_rule,
+                                                                      &pattern_or_name);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+               status = lttng_event_rule_log4j_logging_get_name_pattern(&event_rule,
+                                                                        &pattern_or_name);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+               status = lttng_event_rule_python_logging_get_name_pattern(&event_rule,
+                                                                         &pattern_or_name);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING:
+               status = lttng_event_rule_log4j2_logging_get_name_pattern(&event_rule,
+                                                                         &pattern_or_name);
+               break;
+       default:
+               std::abort();
+       }
+
+       if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
+               return nonstd::nullopt;
+       }
+
+       LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK);
+       LTTNG_ASSERT(pattern_or_name);
+
+       return pattern_or_name;
+}
+} /* namespace */
+
 /*
  * Command LTTNG_DISABLE_EVENT processed by the client thread.
+ *
+ * Filter and exclusions are simply not handled by the disable event command
+ * at this time.
  */
-int cmd_disable_event(struct command_ctx *cmd_ctx,
-                     ltt_session::locked_ref& locked_session,
-                     struct lttng_event *event,
-                     char *filter_expression,
-                     struct lttng_bytecode *bytecode,
-                     struct lttng_event_exclusion *exclusion)
+lttng_error_code cmd_disable_event(struct command_ctx *cmd_ctx,
+                                  ltt_session::locked_ref& locked_session,
+                                  struct lttng_event *event,
+                                  char *raw_filter_expression,
+                                  struct lttng_bytecode *raw_bytecode,
+                                  struct lttng_event_exclusion *raw_exclusion,
+                                  lttng::event_rule_uptr event_rule)
 {
        int ret;
        const ltt_session& session = *locked_session;
-       const char *event_name;
+       const char *event_name = event->name;
        const char *channel_name = cmd_ctx->lsm.u.disable.channel_name;
        const enum lttng_domain_type domain = cmd_ctx->lsm.domain.type;
 
        DBG("Disable event command for event \'%s\'", event->name);
 
-       /*
-        * Filter and exclusions are simply not handled by the
-        * disable event command at this time.
-        *
-        * FIXME
-        */
-       (void) filter_expression;
-       (void) exclusion;
+       const auto filter_expression =
+               lttng::make_unique_wrapper<char, lttng::memory::free>(raw_filter_expression);
+       const auto bytecode =
+               lttng::make_unique_wrapper<lttng_bytecode, lttng::memory::free>(raw_bytecode);
+       const auto exclusion =
+               lttng::make_unique_wrapper<lttng_event_exclusion, lttng::memory::free>(
+                       raw_exclusion);
+
+       if (!event_rule && event->type != LTTNG_EVENT_ALL) {
+               /* LTTNG_EVENT_ALL is the only case where we don't expect an event rule. */
+               return LTTNG_ERR_INVALID_PROTOCOL;
+       }
 
        /* Ignore the presence of filter or exclusion for the event */
        event->filter = 0;
        event->exclusion = 0;
 
-       event_name = event->name;
+       if (channel_name[0] == '\0') {
+               switch (cmd_ctx->lsm.domain.type) {
+               case LTTNG_DOMAIN_LOG4J:
+                       channel_name = DEFAULT_LOG4J_CHANNEL_NAME;
+                       break;
+               case LTTNG_DOMAIN_LOG4J2:
+                       channel_name = DEFAULT_LOG4J2_CHANNEL_NAME;
+                       break;
+               case LTTNG_DOMAIN_JUL:
+                       channel_name = DEFAULT_JUL_CHANNEL_NAME;
+                       break;
+               case LTTNG_DOMAIN_PYTHON:
+                       channel_name = DEFAULT_PYTHON_CHANNEL_NAME;
+                       break;
+               default:
+                       channel_name = DEFAULT_CHANNEL_NAME;
+                       break;
+               }
+       }
 
        const lttng::urcu::read_lock_guard read_lock;
 
        /* Error out on unhandled search criteria */
        if (event->loglevel_type || event->loglevel != -1 || event->enabled || event->pid ||
            event->filter || event->exclusion) {
-               ret = LTTNG_ERR_UNK;
-               goto error;
+               return LTTNG_ERR_UNK;
        }
 
+       const bool pattern_disables_all = lttng::c_string_view(event_name) == "";
+
        switch (domain) {
        case LTTNG_DOMAIN_KERNEL:
        {
@@ -1771,14 +2050,12 @@ int cmd_disable_event(struct command_ctx *cmd_ctx,
                 * to be provided.
                 */
                if (ksess->has_non_default_channel && channel_name[0] == '\0') {
-                       ret = LTTNG_ERR_NEED_CHANNEL_NAME;
-                       goto error_unlock;
+                       return LTTNG_ERR_NEED_CHANNEL_NAME;
                }
 
                kchan = trace_kernel_get_channel_by_name(channel_name, ksess);
                if (kchan == nullptr) {
-                       ret = LTTNG_ERR_KERN_CHAN_NOT_FOUND;
-                       goto error_unlock;
+                       return LTTNG_ERR_KERN_CHAN_NOT_FOUND;
                }
 
                switch (event->type) {
@@ -1788,18 +2065,17 @@ int cmd_disable_event(struct command_ctx *cmd_ctx,
                case LTTNG_EVENT_PROBE:
                case LTTNG_EVENT_FUNCTION:
                case LTTNG_EVENT_FUNCTION_ENTRY: /* fall-through */
-                       if (event_name[0] == '\0') {
+                       if (pattern_disables_all) {
                                ret = event_kernel_disable_event(kchan, nullptr, event->type);
                        } else {
                                ret = event_kernel_disable_event(kchan, event_name, event->type);
                        }
                        if (ret != LTTNG_OK) {
-                               goto error_unlock;
+                               return static_cast<lttng_error_code>(ret);
                        }
                        break;
                default:
-                       ret = LTTNG_ERR_UNK;
-                       goto error_unlock;
+                       return LTTNG_ERR_UNK;
                }
 
                kernel_wait_quiescent();
@@ -1813,8 +2089,7 @@ int cmd_disable_event(struct command_ctx *cmd_ctx,
                usess = session.ust_session;
 
                if (validate_ust_event_name(event_name)) {
-                       ret = LTTNG_ERR_INVALID_EVENT_NAME;
-                       goto error_unlock;
+                       return LTTNG_ERR_INVALID_EVENT_NAME;
                }
 
                /*
@@ -1823,34 +2098,28 @@ int cmd_disable_event(struct command_ctx *cmd_ctx,
                 * to be provided.
                 */
                if (usess->has_non_default_channel && channel_name[0] == '\0') {
-                       ret = LTTNG_ERR_NEED_CHANNEL_NAME;
-                       goto error_unlock;
+                       return LTTNG_ERR_NEED_CHANNEL_NAME;
                }
 
                uchan = trace_ust_find_channel_by_name(usess->domain_global.channels, channel_name);
                if (uchan == nullptr) {
-                       ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
-                       goto error_unlock;
+                       return LTTNG_ERR_UST_CHAN_NOT_FOUND;
                }
 
                switch (event->type) {
                case LTTNG_EVENT_ALL:
-                       /*
-                        * An empty event name means that everything
-                        * should be disabled.
-                        */
-                       if (event->name[0] == '\0') {
+                       if (pattern_disables_all) {
                                ret = event_ust_disable_all_tracepoints(usess, uchan);
                        } else {
                                ret = event_ust_disable_tracepoint(usess, uchan, event_name);
                        }
+
                        if (ret != LTTNG_OK) {
-                               goto error_unlock;
+                               return static_cast<lttng_error_code>(ret);
                        }
                        break;
                default:
-                       ret = LTTNG_ERR_UNK;
-                       goto error_unlock;
+                       return LTTNG_ERR_UNK;
                }
 
                DBG3("Disable UST event %s in channel %s completed", event_name, channel_name);
@@ -1870,43 +2139,43 @@ int cmd_disable_event(struct command_ctx *cmd_ctx,
                case LTTNG_EVENT_ALL:
                        break;
                default:
-                       ret = LTTNG_ERR_UNK;
-                       goto error_unlock;
+                       return LTTNG_ERR_UNK;
                }
 
                agt = trace_ust_find_agent(usess, domain);
                if (!agt) {
-                       ret = -LTTNG_ERR_UST_EVENT_NOT_FOUND;
-                       goto error_unlock;
+                       return LTTNG_ERR_UST_EVENT_NOT_FOUND;
                }
-               /*
-                * An empty event name means that everything
-                * should be disabled.
-                */
-               if (event->name[0] == '\0') {
+
+               if (pattern_disables_all) {
                        ret = event_agent_disable_all(usess, agt);
                } else {
                        ret = event_agent_disable(usess, agt, event_name);
                }
+
                if (ret != LTTNG_OK) {
-                       goto error_unlock;
+                       return static_cast<lttng_error_code>(ret);
                }
 
                break;
        }
        default:
-               ret = LTTNG_ERR_UND;
-               goto error_unlock;
+               return LTTNG_ERR_UND;
        }
 
-       ret = LTTNG_OK;
+       for (const auto& pair : session.get_domain(get_domain_class_from_ctl_domain_type(domain))
+                                       .get_channel(channel_name)
+                                       .event_rules) {
+               auto& event_rule_cfg = *pair.second;
 
-error_unlock:
-error:
-       free(exclusion);
-       free(bytecode);
-       free(filter_expression);
-       return ret;
+               const auto this_pattern_or_name =
+                       get_event_rule_pattern_or_name(*event_rule_cfg.event_rule);
+               if (pattern_disables_all || (*this_pattern_or_name == event_name)) {
+                       event_rule_cfg.disable();
+               }
+       }
+
+       return LTTNG_OK;
 }
 
 /*
@@ -2070,25 +2339,70 @@ end:
        return ret;
 }
 
+namespace {
+lttng::event_rule_uptr create_agent_internal_event_rule(lttng_domain_type agent_domain,
+                                                       lttng::c_string_view filter_expression)
+{
+       lttng::event_rule_uptr event_rule(lttng_event_rule_user_tracepoint_create());
+
+       if (!event_rule) {
+               LTTNG_THROW_POSIX("Failed to allocate agent internal user space tracer event rule",
+                                 ENOMEM);
+       }
+
+       const auto set_pattern_ret = lttng_event_rule_user_tracepoint_set_name_pattern(
+               event_rule.get(), event_get_default_agent_ust_name(agent_domain));
+       if (set_pattern_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+               LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+                       "Failed to set agent LTTng-UST event name as event-rule name pattern: domain={}",
+                       agent_domain));
+       }
+
+       if (filter_expression) {
+               const auto set_filter_ret = lttng_event_rule_user_tracepoint_set_filter(
+                       event_rule.get(), filter_expression.data());
+               if (set_filter_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                       LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+                               "Failed to set agent LTTng-UST event filter expression as event-rule filter: domain={}",
+                               filter_expression));
+               }
+       }
+
+       return event_rule;
+}
+} /* namespace */
+
 /*
  * Internal version of cmd_enable_event() with a supplemental
  * "internal_event" flag which is used to enable internal events which should
  * be hidden from clients. Such events are used in the agent implementation to
  * enable the events through which all "agent" events are funeled.
  */
-static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
-                            const struct lttng_domain *domain,
-                            char *channel_name,
-                            struct lttng_event *event,
-                            char *filter_expression,
-                            struct lttng_bytecode *filter,
-                            struct lttng_event_exclusion *exclusion,
-                            int wpipe,
-                            bool internal_event)
+static lttng_error_code _cmd_enable_event(ltt_session::locked_ref& locked_session,
+                                         const struct lttng_domain *domain,
+                                         char *channel_name,
+                                         struct lttng_event *event,
+                                         char *raw_filter_expression,
+                                         struct lttng_bytecode *raw_bytecode,
+                                         struct lttng_event_exclusion *raw_exclusion,
+                                         int wpipe,
+                                         bool internal_event,
+                                         lttng::event_rule_uptr event_rule)
 {
+       if (!event_rule) {
+               return LTTNG_ERR_INVALID_PROTOCOL;
+       }
+
        int ret = 0, channel_created = 0;
        struct lttng_channel *attr = nullptr;
-       const ltt_session& session = *locked_session;
+       ltt_session& session = *locked_session;
+
+       auto filter_expression =
+               lttng::make_unique_wrapper<char, lttng::memory::free>(raw_filter_expression);
+       auto bytecode =
+               lttng::make_unique_wrapper<lttng_bytecode, lttng::memory::free>(raw_bytecode);
+       auto exclusion = lttng::make_unique_wrapper<lttng_event_exclusion, lttng::memory::free>(
+               raw_exclusion);
 
        LTTNG_ASSERT(event);
        LTTNG_ASSERT(channel_name);
@@ -2108,12 +2422,13 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
        }
 
        const lttng::urcu::read_lock_guard read_lock;
+       const auto *user_visible_channel_name = channel_name[0] == '\0' ? DEFAULT_CHANNEL_NAME :
+                                                                         channel_name;
 
        /* If we have a filter, we must have its filter expression. */
-       if (!!filter_expression ^ !!filter) {
+       if (!!filter_expression ^ !!bytecode) {
                DBG("Refusing to enable recording event rule as it has an inconsistent filter expression and bytecode specification");
-               ret = LTTNG_ERR_INVALID;
-               goto error;
+               return LTTNG_ERR_INVALID;
        }
 
        switch (domain->type) {
@@ -2127,26 +2442,25 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                 * to be provided.
                 */
                if (session.kernel_session->has_non_default_channel && channel_name[0] == '\0') {
-                       ret = LTTNG_ERR_NEED_CHANNEL_NAME;
-                       goto error;
+                       return LTTNG_ERR_NEED_CHANNEL_NAME;
                }
 
                kchan = trace_kernel_get_channel_by_name(channel_name, session.kernel_session);
                if (kchan == nullptr) {
                        attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL, LTTNG_BUFFER_GLOBAL);
                        if (attr == nullptr) {
-                               ret = LTTNG_ERR_FATAL;
-                               goto error;
+                               return LTTNG_ERR_FATAL;
                        }
+
                        if (lttng_strncpy(attr->name, channel_name, sizeof(attr->name))) {
-                               ret = LTTNG_ERR_INVALID;
-                               goto error;
+                               return LTTNG_ERR_INVALID;
                        }
 
-                       ret = cmd_enable_channel_internal(locked_session, domain, attr, wpipe);
+                       ret = cmd_enable_channel_internal(locked_session, domain, *attr, wpipe);
                        if (ret != LTTNG_OK) {
-                               goto error;
+                               return static_cast<lttng_error_code>(ret);
                        }
+
                        channel_created = 1;
                }
 
@@ -2154,8 +2468,7 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                kchan = trace_kernel_get_channel_by_name(channel_name, session.kernel_session);
                if (kchan == nullptr) {
                        /* This sould not happen... */
-                       ret = LTTNG_ERR_FATAL;
-                       goto error;
+                       return LTTNG_ERR_FATAL;
                }
 
                switch (event->type) {
@@ -2170,35 +2483,37 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                         * event.
                         */
                        if (filter_expression) {
-                               filter_expression_a = strdup(filter_expression);
+                               filter_expression_a = strdup(filter_expression.get());
                                if (!filter_expression_a) {
-                                       ret = LTTNG_ERR_FATAL;
-                                       goto error;
+                                       return LTTNG_ERR_FATAL;
                                }
                        }
-                       if (filter) {
-                               filter_a = zmalloc<lttng_bytecode>(sizeof(*filter_a) + filter->len);
+
+                       if (bytecode) {
+                               filter_a =
+                                       zmalloc<lttng_bytecode>(sizeof(*filter_a) + bytecode->len);
                                if (!filter_a) {
                                        free(filter_expression_a);
-                                       ret = LTTNG_ERR_FATAL;
-                                       goto error;
+                                       return LTTNG_ERR_FATAL;
                                }
-                               memcpy(filter_a, filter, sizeof(*filter_a) + filter->len);
+
+                               memcpy(filter_a, bytecode.get(), sizeof(*filter_a) + bytecode->len);
                        }
+
                        event->type = LTTNG_EVENT_TRACEPOINT; /* Hack */
-                       ret = event_kernel_enable_event(kchan, event, filter_expression, filter);
-                       /* We have passed ownership */
-                       filter_expression = nullptr;
-                       filter = nullptr;
+                       ret = event_kernel_enable_event(
+                               kchan, event, filter_expression.release(), bytecode.release());
                        if (ret != LTTNG_OK) {
                                if (channel_created) {
                                        /* Let's not leak a useless channel. */
                                        kernel_destroy_channel(kchan);
                                }
+
                                free(filter_expression_a);
                                free(filter_a);
-                               goto error;
+                               return static_cast<lttng_error_code>(ret);
                        }
+
                        event->type = LTTNG_EVENT_SYSCALL; /* Hack */
                        ret = event_kernel_enable_event(
                                kchan, event, filter_expression_a, filter_a);
@@ -2206,8 +2521,9 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                        filter_expression_a = nullptr;
                        filter_a = nullptr;
                        if (ret != LTTNG_OK) {
-                               goto error;
+                               return static_cast<lttng_error_code>(ret);
                        }
+
                        break;
                }
                case LTTNG_EVENT_PROBE:
@@ -2215,30 +2531,28 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                case LTTNG_EVENT_FUNCTION:
                case LTTNG_EVENT_FUNCTION_ENTRY:
                case LTTNG_EVENT_TRACEPOINT:
-                       ret = event_kernel_enable_event(kchan, event, filter_expression, filter);
-                       /* We have passed ownership */
-                       filter_expression = nullptr;
-                       filter = nullptr;
+                       ret = event_kernel_enable_event(
+                               kchan, event, filter_expression.release(), bytecode.release());
                        if (ret != LTTNG_OK) {
                                if (channel_created) {
                                        /* Let's not leak a useless channel. */
                                        kernel_destroy_channel(kchan);
                                }
-                               goto error;
+
+                               return static_cast<lttng_error_code>(ret);
                        }
+
                        break;
                case LTTNG_EVENT_SYSCALL:
-                       ret = event_kernel_enable_event(kchan, event, filter_expression, filter);
-                       /* We have passed ownership */
-                       filter_expression = nullptr;
-                       filter = nullptr;
+                       ret = event_kernel_enable_event(
+                               kchan, event, filter_expression.release(), bytecode.release());
                        if (ret != LTTNG_OK) {
-                               goto error;
+                               return static_cast<lttng_error_code>(ret);
                        }
+
                        break;
                default:
-                       ret = LTTNG_ERR_UNK;
-                       goto error;
+                       return LTTNG_ERR_UNK;
                }
 
                kernel_wait_quiescent();
@@ -2257,8 +2571,7 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                 * to be provided.
                 */
                if (usess->has_non_default_channel && channel_name[0] == '\0') {
-                       ret = LTTNG_ERR_NEED_CHANNEL_NAME;
-                       goto error;
+                       return LTTNG_ERR_NEED_CHANNEL_NAME;
                }
 
                /* Get channel from global UST domain */
@@ -2267,17 +2580,16 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                        /* Create default channel */
                        attr = channel_new_default_attr(LTTNG_DOMAIN_UST, usess->buffer_type);
                        if (attr == nullptr) {
-                               ret = LTTNG_ERR_FATAL;
-                               goto error;
+                               return LTTNG_ERR_FATAL;
                        }
+
                        if (lttng_strncpy(attr->name, channel_name, sizeof(attr->name))) {
-                               ret = LTTNG_ERR_INVALID;
-                               goto error;
+                               return LTTNG_ERR_INVALID;
                        }
 
-                       ret = cmd_enable_channel_internal(locked_session, domain, attr, wpipe);
+                       ret = cmd_enable_channel_internal(locked_session, domain, *attr, wpipe);
                        if (ret != LTTNG_OK) {
-                               goto error;
+                               return static_cast<lttng_error_code>(ret);
                        }
 
                        /* Get the newly created channel reference back */
@@ -2292,8 +2604,7 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                         * are assigned to a userspace subdomain (JUL, Log4J,
                         * Python, etc.).
                         */
-                       ret = LTTNG_ERR_INVALID_CHANNEL_DOMAIN;
-                       goto error;
+                       return LTTNG_ERR_INVALID_CHANNEL_DOMAIN;
                }
 
                if (!internal_event) {
@@ -2304,23 +2615,22 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                        ret = validate_ust_event_name(event->name);
                        if (ret) {
                                WARN("Userspace event name %s failed validation.", event->name);
-                               ret = LTTNG_ERR_INVALID_EVENT_NAME;
-                               goto error;
+                               return LTTNG_ERR_INVALID_EVENT_NAME;
                        }
                }
 
                /* At this point, the session and channel exist on the tracer */
-               ret = event_ust_enable_tracepoint(
-                       usess, uchan, event, filter_expression, filter, exclusion, internal_event);
-               /* We have passed ownership */
-               filter_expression = nullptr;
-               filter = nullptr;
-               exclusion = nullptr;
-               if (ret == LTTNG_ERR_UST_EVENT_ENABLED) {
-                       goto already_enabled;
-               } else if (ret != LTTNG_OK) {
-                       goto error;
+               ret = event_ust_enable_tracepoint(usess,
+                                                 uchan,
+                                                 event,
+                                                 filter_expression.release(),
+                                                 bytecode.release(),
+                                                 exclusion.release(),
+                                                 internal_event);
+               if (ret != LTTNG_OK) {
+                       return static_cast<lttng_error_code>(ret);
                }
+
                break;
        }
        case LTTNG_DOMAIN_LOG4J:
@@ -2334,21 +2644,23 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                struct lttng_domain tmp_dom;
                struct ltt_ust_session *usess = session.ust_session;
 
+               lttng::event_rule_uptr internal_event_rule =
+                       create_agent_internal_event_rule(domain->type, filter_expression.get());
+
                LTTNG_ASSERT(usess);
 
                if (!agent_tracing_is_enabled()) {
                        DBG("Attempted to enable an event in an agent domain but the agent thread is not running");
-                       ret = LTTNG_ERR_AGENT_TRACING_DISABLED;
-                       goto error;
+                       return LTTNG_ERR_AGENT_TRACING_DISABLED;
                }
 
                agt = trace_ust_find_agent(usess, domain->type);
                if (!agt) {
                        agt = agent_create(domain->type);
                        if (!agt) {
-                               ret = LTTNG_ERR_NOMEM;
-                               goto error;
+                               return LTTNG_ERR_NOMEM;
                        }
+
                        agent_add(agt, usess->agents);
                }
 
@@ -2359,9 +2671,9 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                uevent.loglevel = -1;
                default_event_name = event_get_default_agent_ust_name(domain->type);
                if (!default_event_name) {
-                       ret = LTTNG_ERR_FATAL;
-                       goto error;
+                       return LTTNG_ERR_FATAL;
                }
+
                strncpy(uevent.name, default_event_name, sizeof(uevent.name));
                uevent.name[sizeof(uevent.name) - 1] = '\0';
 
@@ -2391,30 +2703,27 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                        abort();
                }
 
+               user_visible_channel_name = default_chan_name;
+
                {
                        char *filter_expression_copy = nullptr;
-                       struct lttng_bytecode *filter_copy = nullptr;
+                       struct lttng_bytecode *bytecode_copy = nullptr;
 
-                       if (filter) {
+                       if (bytecode) {
                                const size_t filter_size =
-                                       sizeof(struct lttng_bytecode) + filter->len;
+                                       sizeof(struct lttng_bytecode) + bytecode->len;
 
-                               filter_copy = zmalloc<lttng_bytecode>(filter_size);
-                               if (!filter_copy) {
-                                       ret = LTTNG_ERR_NOMEM;
-                                       goto error;
+                               bytecode_copy = zmalloc<lttng_bytecode>(filter_size);
+                               if (!bytecode_copy) {
+                                       return LTTNG_ERR_NOMEM;
                                }
-                               memcpy(filter_copy, filter, filter_size);
 
-                               filter_expression_copy = strdup(filter_expression);
-                               if (!filter_expression) {
-                                       ret = LTTNG_ERR_NOMEM;
-                               }
+                               memcpy(bytecode_copy, bytecode.get(), filter_size);
 
-                               if (!filter_expression_copy || !filter_copy) {
-                                       free(filter_expression_copy);
-                                       free(filter_copy);
-                                       goto error;
+                               filter_expression_copy = strdup(filter_expression.get());
+                               if (!filter_expression_copy) {
+                                       free(bytecode_copy);
+                                       return LTTNG_ERR_NOMEM;
                                }
                        }
 
@@ -2423,45 +2732,45 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
                                                        (char *) default_chan_name,
                                                        &uevent,
                                                        filter_expression_copy,
-                                                       filter_copy,
+                                                       bytecode_copy,
                                                        nullptr,
-                                                       wpipe);
+                                                       wpipe,
+                                                       std::move(internal_event_rule));
                }
 
-               if (ret == LTTNG_ERR_UST_EVENT_ENABLED) {
-                       goto already_enabled;
-               } else if (ret != LTTNG_OK) {
-                       goto error;
+               if (ret != LTTNG_OK) {
+                       return static_cast<lttng_error_code>(ret);
                }
 
                /* The wild card * means that everything should be enabled. */
                if (strncmp(event->name, "*", 1) == 0 && strlen(event->name) == 1) {
-                       ret = event_agent_enable_all(usess, agt, event, filter, filter_expression);
+                       ret = event_agent_enable_all(
+                               usess, agt, event, bytecode.release(), filter_expression.release());
                } else {
-                       ret = event_agent_enable(usess, agt, event, filter, filter_expression);
+                       ret = event_agent_enable(
+                               usess, agt, event, bytecode.release(), filter_expression.release());
                }
-               filter = nullptr;
-               filter_expression = nullptr;
+
                if (ret != LTTNG_OK) {
-                       goto error;
+                       return static_cast<lttng_error_code>(ret);
                }
 
                break;
        }
        default:
-               ret = LTTNG_ERR_UND;
-               goto error;
+               return LTTNG_ERR_UND;
        }
 
-       ret = LTTNG_OK;
+       auto& channel_cfg = session.get_domain(get_domain_class_from_ctl_domain_type(domain->type))
+                                   .get_channel(user_visible_channel_name);
+       try {
+               channel_cfg.get_event_rule_configuration(*event_rule).enable();
+       } catch (const lttng::sessiond::exceptions::event_rule_configuration_not_found_error& ex) {
+               DBG("%s", ex.what());
+               channel_cfg.add_event_rule_configuration(true, std::move(event_rule));
+       }
 
-already_enabled:
-error:
-       free(filter_expression);
-       free(filter);
-       free(exclusion);
-       channel_attr_destroy(attr);
-       return ret;
+       return LTTNG_OK;
 }
 
 /*
@@ -2474,7 +2783,8 @@ int cmd_enable_event(struct command_ctx *cmd_ctx,
                     char *filter_expression,
                     struct lttng_event_exclusion *exclusion,
                     struct lttng_bytecode *bytecode,
-                    int wpipe)
+                    int wpipe,
+                    lttng::event_rule_uptr event_rule)
 {
        int ret;
        /*
@@ -2498,7 +2808,8 @@ int cmd_enable_event(struct command_ctx *cmd_ctx,
                                bytecode,
                                exclusion,
                                wpipe,
-                               false);
+                               false,
+                               std::move(event_rule));
        filter_expression = nullptr;
        bytecode = nullptr;
        exclusion = nullptr;
@@ -2517,7 +2828,8 @@ static int cmd_enable_event_internal(ltt_session::locked_ref& locked_session,
                                     char *filter_expression,
                                     struct lttng_bytecode *filter,
                                     struct lttng_event_exclusion *exclusion,
-                                    int wpipe)
+                                    int wpipe,
+                                    lttng::event_rule_uptr event_rule)
 {
        return _cmd_enable_event(locked_session,
                                 domain,
@@ -2527,7 +2839,8 @@ static int cmd_enable_event_internal(ltt_session::locked_ref& locked_session,
                                 filter,
                                 exclusion,
                                 wpipe,
-                                true);
+                                true,
+                                std::move(event_rule));
 }
 
 /*
@@ -3045,7 +3358,7 @@ int cmd_set_consumer_uri(const ltt_session::locked_ref& session,
         * Make sure to set the session in output mode after we set URI since a
         * session can be created without URL (thus flagged in no output mode).
         */
-       session->output_traces = 1;
+       session->output_traces = true;
        if (ksess) {
                ksess->output_traces = 1;
        }
@@ -3225,7 +3538,7 @@ cmd_create_session_from_descriptor(struct lttng_session_descriptor *descriptor,
 
        switch (lttng_session_descriptor_get_type(descriptor)) {
        case LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT:
-               new_session->snapshot_mode = 1;
+               new_session->snapshot_mode = true;
                break;
        case LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE:
                new_session->live_timer =
index 6b6dfedf5de0c9de2d16824ef6f1d8ba6b516d0f..73b25aa2a99da93aa67bfdf8cd4a4767d774e306 100644 (file)
@@ -15,6 +15,7 @@
 #include "session.hpp"
 #include "snapshot-output.hpp"
 
+#include <common/ctl/memory.hpp>
 #include <common/tracker.hpp>
 
 #include <lttng/kernel.h>
@@ -85,12 +86,13 @@ cmd_process_attr_tracker_get_inclusion_set(const ltt_session::locked_ref& sessio
                                           struct lttng_process_attr_values **values);
 
 /* Event commands */
-int cmd_disable_event(struct command_ctx *cmd_ctx,
-                     ltt_session::locked_ref& locked_session,
-                     struct lttng_event *event,
-                     char *filter_expression,
-                     struct lttng_bytecode *filter,
-                     struct lttng_event_exclusion *exclusion);
+lttng_error_code cmd_disable_event(struct command_ctx *cmd_ctx,
+                                  ltt_session::locked_ref& locked_session,
+                                  struct lttng_event *event,
+                                  char *filter_expression,
+                                  struct lttng_bytecode *filter,
+                                  struct lttng_event_exclusion *exclusion,
+                                  lttng::event_rule_uptr event_rule);
 int cmd_add_context(struct command_ctx *cmd_ctx,
                    ltt_session::locked_ref& locked_session,
                    const struct lttng_event_context *event_context,
@@ -106,7 +108,8 @@ int cmd_enable_event(struct command_ctx *cmd_ctx,
                     char *filter_expression,
                     struct lttng_event_exclusion *exclusion,
                     struct lttng_bytecode *bytecode,
-                    int wpipe);
+                    int wpipe,
+                    lttng::event_rule_uptr event_rule);
 
 /* Trace session action commands */
 int cmd_start_trace(const ltt_session::locked_ref& session);
diff --git a/src/bin/lttng-sessiond/domain.cpp b/src/bin/lttng-sessiond/domain.cpp
new file mode 100644 (file)
index 0000000..2964787
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "domain.hpp"
+
+lttng::sessiond::exceptions::channel_not_found_error::channel_not_found_error(
+       std::string channel_name_, const lttng::source_location& source_location_) :
+       lttng::runtime_error(
+               fmt::format("No channel with the given name in domain: channel_name=`{}`",
+                           channel_name_),
+               source_location_),
+       channel_name{ std::move(channel_name_) }
+{
+}
\ No newline at end of file
diff --git a/src/bin/lttng-sessiond/domain.hpp b/src/bin/lttng-sessiond/domain.hpp
new file mode 100644 (file)
index 0000000..e88be85
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_SESSIOND_DOMAIN_HPP
+#define LTTNG_SESSIOND_DOMAIN_HPP
+
+#include "recording-channel-configuration.hpp"
+
+#include <common/exception.hpp>
+#include <common/format.hpp>
+#include <common/make-unique.hpp>
+#include <common/string-utils/c-string-view.hpp>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+namespace lttng {
+namespace sessiond {
+
+enum class domain_class {
+       USER_SPACE,
+       KERNEL_SPACE,
+       LOG4J,
+       LOG4J2,
+       JAVA_UTIL_LOGGING,
+       PYTHON_LOGGING,
+};
+
+#define LTTNG_THROW_CHANNEL_NOT_FOUND_BY_NAME_ERROR(channel_name)                \
+       throw lttng::sessiond::exceptions::channel_not_found_error(channel_name, \
+                                                                  LTTNG_SOURCE_LOCATION())
+
+namespace exceptions {
+/*
+ * @class channel_not_found_error
+ * @brief Represents a channel-not-found error and provides the name of the channel looked-up
+ * for use by error-reporting code.
+ */
+class channel_not_found_error : public lttng::runtime_error {
+public:
+       explicit channel_not_found_error(std::string channel_name,
+                                        const lttng::source_location& source_location);
+
+       const std::string channel_name;
+};
+} /* namespace exceptions */
+
+/*
+ * A channel configuration represents the configuration of a recording session's
+ * channel at a given point in time. It belongs to a single recording session.
+ */
+class domain {
+public:
+       explicit domain(lttng::sessiond::domain_class domain_class) : domain_class_(domain_class)
+       {
+       }
+
+       virtual ~domain() = default;
+
+       domain(const domain&) = delete;
+       domain(domain&&) = delete;
+       domain& operator=(const domain&) = delete;
+       domain& operator=(domain&&) = delete;
+
+       /* Add a channel to the domain by constructing it in place. */
+       template <typename... Args>
+       recording_channel_configuration& add_channel(Args&&...args)
+       {
+               return _add_channel(lttng::make_unique<recording_channel_configuration>(
+                       std::forward<Args>(args)...));
+       }
+
+       /* Lookup by name, get non-const reference. */
+       virtual recording_channel_configuration& get_channel(const lttng::c_string_view& name) = 0;
+
+       /* Lookup by name, get const reference. */
+       const recording_channel_configuration& get_channel(const lttng::c_string_view& name) const
+       {
+               /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */
+               return const_cast<domain *>(this)->get_channel(name);
+       }
+
+       const lttng::sessiond::domain_class domain_class_;
+
+private:
+       virtual recording_channel_configuration&
+       _add_channel(recording_channel_configuration::uptr new_channel) = 0;
+};
+
+class multi_channel_domain : public domain {
+       using channels_t = std::unordered_map<std::string, recording_channel_configuration::uptr>;
+
+public:
+       explicit multi_channel_domain(domain_class domain_class) : domain(domain_class)
+       {
+       }
+
+       ~multi_channel_domain() override = default;
+       multi_channel_domain(multi_channel_domain&& other) noexcept :
+               domain(other.domain_class_), channels(std::move(other.channels))
+       {
+       }
+
+       multi_channel_domain(const multi_channel_domain&) = delete;
+       multi_channel_domain& operator=(const multi_channel_domain&) = delete;
+       multi_channel_domain& operator=(multi_channel_domain&&) = delete;
+
+       /* Lookup by name, get non-const reference. */
+       recording_channel_configuration& get_channel(const lttng::c_string_view& name) override
+       {
+               const auto it = channels.find(name.data());
+               if (it == channels.end()) {
+                       LTTNG_THROW_CHANNEL_NOT_FOUND_BY_NAME_ERROR(name);
+               }
+
+               return *(it->second);
+       }
+
+       /* Iterate over channels (non-const) */
+       channels_t::iterator begin()
+       {
+               return channels.begin();
+       }
+
+       channels_t::iterator end()
+       {
+               return channels.end();
+       }
+
+       /* Iterate over channels (const) */
+       channels_t::const_iterator begin() const
+       {
+               return channels.begin();
+       }
+
+       channels_t::const_iterator end() const
+       {
+               return channels.end();
+       }
+
+private:
+       recording_channel_configuration&
+       _add_channel(recording_channel_configuration::uptr new_channel) override
+       {
+               const auto& name = new_channel->name;
+
+               auto result = channels.emplace(name, std::move(new_channel));
+               if (!result.second) {
+                       throw std::runtime_error(fmt::format(
+                               "Failed to add channel to domain, name already in use: channel_name=`{}`",
+                               name));
+               }
+
+               return *(result.first->second);
+       }
+
+       channels_t channels;
+};
+
+} /* namespace sessiond */
+} /* namespace lttng */
+
+/*
+ * Specialize fmt::formatter for domain_class.
+ *
+ * Due to a bug in g++ < 7.1, this specialization must be enclosed in the fmt namespace,
+ * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480.
+ */
+namespace fmt {
+template <>
+struct formatter<lttng::sessiond::domain_class> : formatter<std::string> {
+       /* Format function to convert enum to string. */
+       template <typename FormatContextType>
+       typename FormatContextType::iterator format(lttng::sessiond::domain_class domain,
+                                                   FormatContextType& ctx) const
+       {
+               auto name = "UNKNOWN";
+
+               switch (domain) {
+               case lttng::sessiond::domain_class::USER_SPACE:
+                       name = "USER_SPACE";
+                       break;
+               case lttng::sessiond::domain_class::KERNEL_SPACE:
+                       name = "KERNEL_SPACE";
+                       break;
+               case lttng::sessiond::domain_class::LOG4J:
+                       name = "LOG4J";
+                       break;
+               case lttng::sessiond::domain_class::LOG4J2:
+                       name = "LOG4J2";
+                       break;
+               case lttng::sessiond::domain_class::JAVA_UTIL_LOGGING:
+                       name = "JAVA_UTIL_LOGGING";
+                       break;
+               case lttng::sessiond::domain_class::PYTHON_LOGGING:
+                       name = "PYTHON_LOGGING";
+                       break;
+               }
+
+               /* Write the string representation to the format context output iterator. */
+               return format_to(ctx.out(), name);
+       }
+};
+} /* namespace fmt */
+
+#endif /* LTTNG_SESSIOND_DOMAIN_HPP */
diff --git a/src/bin/lttng-sessiond/event-rule-configuration.cpp b/src/bin/lttng-sessiond/event-rule-configuration.cpp
new file mode 100644 (file)
index 0000000..75f0281
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "event-rule-configuration.hpp"
+
+namespace ls = lttng::sessiond;
+
+ls::event_rule_configuration::event_rule_configuration(bool is_enabled_,
+                                                      lttng::event_rule_uptr&& event_rule_) :
+       is_enabled(is_enabled_), event_rule(std::move(event_rule_))
+{
+}
+
+void ls::event_rule_configuration::set_enabled(bool enable) noexcept
+{
+       is_enabled = enable;
+}
diff --git a/src/bin/lttng-sessiond/event-rule-configuration.hpp b/src/bin/lttng-sessiond/event-rule-configuration.hpp
new file mode 100644 (file)
index 0000000..2164b45
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_SESSIOND_EVENT_RULE_CONFIGURATION_HPP
+#define LTTNG_SESSIOND_EVENT_RULE_CONFIGURATION_HPP
+
+#include <common/ctl/memory.hpp>
+#include <common/format.hpp>
+
+#include <vendor/optional.hpp>
+
+#include <cstdint>
+#include <string>
+
+namespace lttng {
+namespace sessiond {
+
+/*
+ * An event rule configuration represents the configuration of a channel or map's
+ * event rule at a given point in time. It belongs to a single channel or map.
+ */
+class event_rule_configuration final {
+public:
+       using uptr = std::unique_ptr<event_rule_configuration>;
+
+       event_rule_configuration(bool is_enabled, lttng::event_rule_uptr&& event_rule);
+
+       ~event_rule_configuration() = default;
+       event_rule_configuration(event_rule_configuration&&) = delete;
+       event_rule_configuration(const event_rule_configuration&) = delete;
+       event_rule_configuration& operator=(const event_rule_configuration&) = delete;
+       event_rule_configuration& operator=(event_rule_configuration&&) = delete;
+
+       void enable() noexcept
+       {
+               set_enabled(true);
+       }
+
+       void disable() noexcept
+       {
+               set_enabled(false);
+       }
+
+       void set_enabled(bool enable) noexcept;
+
+       bool is_enabled;
+       const lttng::event_rule_uptr event_rule;
+};
+
+} /* namespace sessiond */
+} /* namespace lttng */
+
+#endif /* LTTNG_SESSIOND_EVENT_RULE_CONFIGURATION_HPP */
diff --git a/src/bin/lttng-sessiond/recording-channel-configuration.cpp b/src/bin/lttng-sessiond/recording-channel-configuration.cpp
new file mode 100644 (file)
index 0000000..6a927f0
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "recording-channel-configuration.hpp"
+
+#include <common/ctl/format.hpp>
+#include <common/error.hpp>
+#include <common/exception.hpp>
+#include <common/format.hpp>
+
+#include <lttng/event-rule/event-rule-internal.hpp>
+
+namespace ls = lttng::sessiond;
+
+ls::exceptions::event_rule_configuration_not_found_error::event_rule_configuration_not_found_error(
+       const lttng_event_rule& event_rule_, const lttng::source_location& source_location_) :
+       lttng::runtime_error(
+               fmt::format("No matching event-rule in channel configuration: event_rule=`{}`",
+                           event_rule_),
+               source_location_)
+{
+}
+
+ls::recording_channel_configuration::recording_channel_configuration(
+       bool is_enabled_,
+       std::string name_,
+       buffer_full_policy_t buffer_full_policy_,
+       buffer_consumption_backend_t buffer_consumption_backend_,
+       std::uint64_t subbuffer_size_bytes_,
+       unsigned int subbuffer_count_,
+       const nonstd::optional<timer_period_us>& switch_timer_period_us_,
+       const nonstd::optional<timer_period_us>& read_timer_period_us_,
+       const nonstd::optional<timer_period_us>& live_timer_period_us_,
+       const nonstd::optional<timer_period_us>& monitor_timer_period_us_,
+       consumption_blocking_policy blocking_policy,
+       const nonstd::optional<std::uint64_t>& trace_file_size_limit_bytes_,
+       const nonstd::optional<unsigned int>& trace_file_count_limit_) :
+       name(std::move(name_)),
+       buffer_full_policy(buffer_full_policy_),
+       buffer_consumption_backend(buffer_consumption_backend_),
+       subbuffer_size_bytes(subbuffer_size_bytes_),
+       subbuffer_count(subbuffer_count_),
+       switch_timer_period_us(switch_timer_period_us_),
+       read_timer_period_us(read_timer_period_us_),
+       live_timer_period_us(live_timer_period_us_),
+       monitor_timer_period_us(monitor_timer_period_us_),
+       consumption_blocking_policy_(std::move(blocking_policy)),
+       trace_file_size_limit_bytes(trace_file_size_limit_bytes_),
+       trace_file_count_limit(trace_file_count_limit_),
+       is_enabled(is_enabled_)
+{
+}
+
+ls::recording_channel_configuration::consumption_blocking_policy::consumption_blocking_policy(
+       ls::recording_channel_configuration::consumption_blocking_policy::mode policy_mode,
+       const nonstd::optional<timer_period_us>& blocking_timeout_us) :
+       mode_(policy_mode), timeout_us(blocking_timeout_us)
+{
+       if (blocking_timeout_us.has_value() !=
+           (policy_mode ==
+            ls::recording_channel_configuration::consumption_blocking_policy::mode::TIMED)) {
+               LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+                       "Invalid timeout argument specified for consumption blocking policy: policy_mode={}, timeout={}",
+                       mode_,
+                       timeout_us));
+       }
+}
+
+void ls::recording_channel_configuration::set_enabled(bool enable) noexcept
+{
+       is_enabled = enable;
+}
+
+const ls::event_rule_configuration&
+ls::recording_channel_configuration::get_event_rule_configuration(
+       const lttng_event_rule& matching_event_rule_to_lookup) const
+{
+       /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */
+       return const_cast<recording_channel_configuration *>(this)->get_event_rule_configuration(
+               matching_event_rule_to_lookup);
+}
+
+ls::event_rule_configuration& ls::recording_channel_configuration::get_event_rule_configuration(
+       const lttng_event_rule& matching_event_rule_to_lookup)
+{
+       const auto it = event_rules.find(std::ref(matching_event_rule_to_lookup));
+       if (it == event_rules.end()) {
+               LTTNG_THROW_EVENT_RULE_CONFIGURATION_NOT_FOUND_ERROR(matching_event_rule_to_lookup);
+       }
+
+       return *(it->second);
+}
diff --git a/src/bin/lttng-sessiond/recording-channel-configuration.hpp b/src/bin/lttng-sessiond/recording-channel-configuration.hpp
new file mode 100644 (file)
index 0000000..6c99465
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_SESSIOND_RECORDING_CHANNEL_CONFIGURATION_HPP
+#define LTTNG_SESSIOND_RECORDING_CHANNEL_CONFIGURATION_HPP
+
+#include "event-rule-configuration.hpp"
+
+#include <common/ctl/memory.hpp>
+#include <common/exception.hpp>
+#include <common/format.hpp>
+#include <common/make-unique.hpp>
+
+#include <lttng/event-rule/event-rule-internal.hpp>
+
+#include <vendor/optional.hpp>
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+namespace lttng {
+namespace sessiond {
+
+#define LTTNG_THROW_EVENT_RULE_CONFIGURATION_NOT_FOUND_ERROR(event_rule)             \
+       throw lttng::sessiond::exceptions::event_rule_configuration_not_found_error( \
+               event_rule, LTTNG_SOURCE_LOCATION())
+
+namespace exceptions {
+/*
+ * @class event_rule_configuration_not_found_error
+ * @brief Represents a event-rule-configuration-not-found error and provides the
+ * name of the channel looked-up for use by error-reporting code.
+ */
+class event_rule_configuration_not_found_error : public lttng::runtime_error {
+public:
+       explicit event_rule_configuration_not_found_error(
+               const lttng_event_rule& event_rule, const lttng::source_location& source_location);
+};
+} /* namespace exceptions */
+
+/*
+ * A recording channel configuration represents the configuration of a recording session's
+ * channel at a given point in time. It belongs to a single recording session.
+ */
+class recording_channel_configuration final {
+public:
+       using uptr = std::unique_ptr<recording_channel_configuration>;
+       using timer_period_us = std::uint64_t;
+
+       enum class buffer_full_policy_t {
+               DISCARD_EVENT,
+               OVERWRITE_OLDEST_PACKET,
+       };
+
+       enum class buffer_consumption_backend_t {
+               MMAP,
+               SPLICE,
+       };
+
+       struct consumption_blocking_policy {
+               enum class mode {
+                       NONE,
+                       TIMED,
+                       UNBOUNDED,
+               };
+
+               explicit consumption_blocking_policy(
+                       mode mode,
+                       const nonstd::optional<timer_period_us>& timeout_us = nonstd::nullopt);
+
+               const mode mode_;
+               /* Only set in TIMED mode. */
+               const nonstd::optional<timer_period_us> timeout_us;
+       };
+
+       recording_channel_configuration(
+               bool is_enabled,
+               std::string name,
+               buffer_full_policy_t buffer_full_policy,
+               buffer_consumption_backend_t buffer_consumption_backend,
+               std::uint64_t subbuffer_size_bytes,
+               unsigned int subbuffer_count,
+               const nonstd::optional<timer_period_us>& switch_timer_period_us,
+               const nonstd::optional<timer_period_us>& read_timer_period_us,
+               const nonstd::optional<timer_period_us>& live_timer_period_us,
+               const nonstd::optional<timer_period_us>& monitor_timer_period_us,
+               consumption_blocking_policy consumption_blocking_policy,
+               const nonstd::optional<std::uint64_t>& trace_file_size_limit_bytes,
+               const nonstd::optional<unsigned int>& trace_file_count_limit);
+
+       ~recording_channel_configuration() = default;
+       recording_channel_configuration(recording_channel_configuration&&) = delete;
+       recording_channel_configuration(const recording_channel_configuration&) = delete;
+       recording_channel_configuration& operator=(const recording_channel_configuration&) = delete;
+       recording_channel_configuration& operator=(recording_channel_configuration&&) = delete;
+
+       void enable() noexcept
+       {
+               set_enabled(true);
+       }
+
+       void disable() noexcept
+       {
+               set_enabled(false);
+       }
+
+       void set_enabled(bool enable) noexcept;
+
+       template <typename... Args>
+       void add_event_rule_configuration(Args&&...args)
+       {
+               auto config =
+                       lttng::make_unique<event_rule_configuration>(std::forward<Args>(args)...);
+
+               event_rules.emplace(std::cref(*config->event_rule), std::move(config));
+       }
+
+       const lttng::sessiond::event_rule_configuration&
+       get_event_rule_configuration(const lttng_event_rule& matching_event_rule_to_lookup) const;
+       lttng::sessiond::event_rule_configuration&
+       get_event_rule_configuration(const lttng_event_rule& matching_event_rule_to_lookup);
+
+       const std::string name;
+       const buffer_full_policy_t buffer_full_policy;
+       const buffer_consumption_backend_t buffer_consumption_backend;
+       const std::uint64_t subbuffer_size_bytes;
+       const unsigned int subbuffer_count;
+       const nonstd::optional<timer_period_us> switch_timer_period_us;
+       const nonstd::optional<timer_period_us> read_timer_period_us;
+       const nonstd::optional<timer_period_us> live_timer_period_us;
+       const nonstd::optional<timer_period_us> monitor_timer_period_us;
+       const consumption_blocking_policy consumption_blocking_policy_;
+       const nonstd::optional<std::uint64_t> trace_file_size_limit_bytes;
+       const nonstd::optional<unsigned int> trace_file_count_limit;
+
+       bool is_enabled;
+
+       std::unordered_map<std::reference_wrapper<const lttng_event_rule>,
+                          event_rule_configuration::uptr,
+                          std::hash<std::reference_wrapper<const lttng_event_rule>>,
+                          lttng_event_rule_ref_equal>
+               event_rules;
+};
+
+} /* namespace sessiond */
+} /* namespace lttng */
+
+/*
+ * Specialize fmt::formatter for consumption_blocking_policy's mode.
+ *
+ * Due to a bug in g++ < 7.1, this specialization must be enclosed in the fmt namespace,
+ * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480.
+ */
+namespace fmt {
+template <>
+struct formatter<lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::mode>
+       : formatter<std::string> {
+       /* Format function to convert enum to string. */
+       template <typename FormatContextType>
+       typename FormatContextType::iterator
+       format(lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::mode
+                      mode,
+              FormatContextType& ctx) const
+       {
+               auto name = "UNKNOWN";
+
+               switch (mode) {
+               case lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::
+                       mode::NONE:
+                       name = "NONE";
+                       break;
+               case lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::
+                       mode::UNBOUNDED:
+                       name = "UNBOUNDED";
+                       break;
+               case lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::
+                       mode::TIMED:
+                       name = "TIMED";
+                       break;
+               }
+
+               /* Write the string representation to the format context output iterator. */
+               return format_to(ctx.out(), name);
+       }
+};
+} /* namespace fmt */
+
+#endif /* LTTNG_SESSIOND_RECORDING_CHANNEL_CONFIGURATION_HPP */
index ee32486e0d0c9709af674e895270ede14f1acb86..298b887c78a26990138ea5d5cc29e6731f357f36 100644 (file)
@@ -496,6 +496,28 @@ void ltt_session::unlock() const noexcept
        ltt_session::_const_session_unlock(*this);
 }
 
+ls::domain& ltt_session::get_domain(ls::domain_class domain)
+{
+       switch (domain) {
+       case ls::domain_class::LOG4J:
+       case ls::domain_class::LOG4J2:
+       case ls::domain_class::JAVA_UTIL_LOGGING:
+       case ls::domain_class::PYTHON_LOGGING:
+       case ls::domain_class::USER_SPACE:
+               return user_space_domain;
+       case ls::domain_class::KERNEL_SPACE:
+               return kernel_space_domain;
+       }
+
+       std::abort();
+}
+
+const ls::domain& ltt_session::get_domain(ls::domain_class domain) const
+{
+       /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */
+       return const_cast<ltt_session *>(this)->get_domain(domain);
+}
+
 /*
  * Release session lock
  */
@@ -1892,4 +1914,4 @@ ls::ust::registry_session *
 ls::user_space_consumer_channel_keys::iterator::_get_registry_session_per_uid()
 {
        return _position._per_uid.current_registry->registry->reg.ust;
-}
\ No newline at end of file
+}
index 74aa76f023bb2f3d6c5935595d2538de63e32bff..58e2bd9a6badc5804660f9e576a48dc8d5b3a3e2 100644 (file)
@@ -9,6 +9,7 @@
 #define _LTT_SESSION_H
 
 #include "consumer.hpp"
+#include "domain.hpp"
 #include "snapshot.hpp"
 #include "trace-kernel.hpp"
 #include "trace-ust.hpp"
@@ -320,6 +321,9 @@ public:
        void lock() const noexcept;
        void unlock() const noexcept;
 
+       lttng::sessiond::domain& get_domain(lttng::sessiond::domain_class domain);
+       const lttng::sessiond::domain& get_domain(lttng::sessiond::domain_class domain) const;
+
        lttng::sessiond::user_space_consumer_channel_keys user_space_consumer_channel_keys() const;
 
        /*
@@ -468,6 +472,11 @@ public:
        struct lttng_dynamic_array clear_notifiers = {};
        /* Session base path override. Set non-null. */
        char *base_path = nullptr;
+
+       lttng::sessiond::multi_channel_domain user_space_domain =
+               lttng::sessiond::multi_channel_domain(lttng::sessiond::domain_class::USER_SPACE);
+       lttng::sessiond::multi_channel_domain kernel_space_domain =
+               lttng::sessiond::multi_channel_domain(lttng::sessiond::domain_class::KERNEL_SPACE);
 };
 
 /*
@@ -597,7 +606,7 @@ public:
 
        query_parameter query_parameter;
 };
-} // namespace exceptions
+} /* namespace exceptions */
 } /* namespace sessiond */
 } /* namespace lttng */
 
index 6f059a1bcc745d9ad7cfce82d54e7eb15516d6f9..f11d2b8342d808339d1186206d7d6677e78e49ac 100644 (file)
@@ -51,6 +51,7 @@ libcommon_lgpl_la_SOURCES = \
        buffer-view.hpp buffer-view.cpp \
        channel.cpp \
        ctl/format.hpp \
+       ctl/memory.hpp \
        compiler.hpp \
        conditions/buffer-usage.cpp \
        conditions/condition.cpp \
@@ -94,6 +95,7 @@ libcommon_lgpl_la_SOURCES = \
        log-level-rule.cpp \
        make-unique.hpp \
        make-unique-wrapper.hpp \
+       math.hpp \
        meta-helpers.hpp \
        mi-lttng.cpp mi-lttng.hpp \
        notification.cpp \
index c82982cfc0a665188872478523c149c809581c1a..e9fc65d137e5d813df440deb6eda824df5c2f73c 100644 (file)
@@ -40,6 +40,138 @@ struct formatter<lttng_buffer_type> : formatter<std::string> {
                return format_to(ctx.out(), name);
        }
 };
+
+template <>
+struct formatter<lttng_domain_type> : formatter<std::string> {
+       template <typename FormatContextType>
+       typename FormatContextType::iterator format(lttng_domain_type domain_type,
+                                                   FormatContextType& ctx) const
+       {
+               auto name = "unknown";
+
+               switch (domain_type) {
+               case LTTNG_DOMAIN_NONE:
+                       name = "none";
+                       break;
+               case LTTNG_DOMAIN_KERNEL:
+                       name = "kernel";
+                       break;
+               case LTTNG_DOMAIN_UST:
+                       name = "user space";
+                       break;
+               case LTTNG_DOMAIN_JUL:
+                       name = "java.util.logging (JUL)";
+                       break;
+               case LTTNG_DOMAIN_LOG4J:
+                       name = "log4j";
+                       break;
+               case LTTNG_DOMAIN_LOG4J2:
+                       name = "log4j2";
+                       break;
+               case LTTNG_DOMAIN_PYTHON:
+                       name = "Python logging";
+                       break;
+               }
+
+               return format_to(ctx.out(), name);
+       }
+};
+
+template <>
+struct formatter<lttng_loglevel_type> : formatter<std::string> {
+       template <typename FormatContextType>
+       typename FormatContextType::iterator format(lttng_loglevel_type loglevel_type,
+                                                   FormatContextType& ctx) const
+       {
+               auto name = "unknown";
+
+               switch (loglevel_type) {
+               case LTTNG_EVENT_LOGLEVEL_ALL:
+                       name = "all";
+                       break;
+               case LTTNG_EVENT_LOGLEVEL_RANGE:
+                       name = "range";
+                       break;
+               case LTTNG_EVENT_LOGLEVEL_SINGLE:
+                       name = "single";
+                       break;
+               }
+
+               return format_to(ctx.out(), name);
+       }
+};
+
+template <>
+struct formatter<lttng_log_level_rule_type> : formatter<std::string> {
+       template <typename FormatContextType>
+       typename FormatContextType::iterator format(lttng_log_level_rule_type rule_type,
+                                                   FormatContextType& ctx) const
+       {
+               auto name = "unknown";
+
+               switch (rule_type) {
+               case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+                       name = "exactly";
+                       break;
+               case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+                       name = "\"at least as severe as\"";
+                       break;
+               case LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN:
+                       break;
+               }
+
+               return format_to(ctx.out(), name);
+       }
+};
+
+template <>
+struct formatter<lttng_event_rule> : formatter<std::string> {
+       template <typename FormatContextType>
+       typename FormatContextType::iterator format(const lttng_event_rule& rule,
+                                                   FormatContextType& ctx) const
+       {
+               const auto rule_type = lttng_event_rule_get_type(&rule);
+               const char *rule_type_name;
+
+               switch (rule_type) {
+               case LTTNG_EVENT_RULE_TYPE_UNKNOWN:
+                       rule_type_name = "UNKNOWN";
+                       break;
+               case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
+                       rule_type_name = "KERNEL_SYSCALL";
+                       break;
+               case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
+                       rule_type_name = "KERNEL_KPROBE";
+                       break;
+               case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
+                       rule_type_name = "KERNEL_TRACEPOINT";
+                       break;
+               case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
+                       rule_type_name = "KERNEL_UPROBE";
+                       break;
+               case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+                       rule_type_name = "USER_TRACEPOINT";
+                       break;
+               case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+                       rule_type_name = "JUL_LOGGING";
+                       break;
+               case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+                       rule_type_name = "LOG4J_LOGGING";
+                       break;
+               case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+                       rule_type_name = "PYTHON_LOGGING";
+                       break;
+               case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING:
+                       rule_type_name = "LOG4J2_LOGGING";
+                       break;
+               default:
+                       std::abort();
+               }
+
+               return format_to(ctx.out(), "{{type={}}}", rule_type_name);
+       }
+};
+
 } /* namespace fmt */
 
-#endif /* LTTNG_COMMON_CTL_FORMAT_H */
\ No newline at end of file
+#endif /* LTTNG_COMMON_CTL_FORMAT_H */
diff --git a/src/common/ctl/memory.hpp b/src/common/ctl/memory.hpp
new file mode 100644 (file)
index 0000000..100365d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_COMMON_CTL_MEMORY_HPP
+#define LTTNG_COMMON_CTL_MEMORY_HPP
+
+#include <common/meta-helpers.hpp>
+
+#include <lttng/lttng.h>
+
+#include <memory>
+#include <vector>
+
+namespace lttng {
+
+using event_rule_uptr = std::unique_ptr<
+       lttng_event_rule,
+       lttng::memory::create_deleter_class<lttng_event_rule, lttng_event_rule_destroy>>;
+
+using kernel_location_uptr =
+       std::unique_ptr<lttng_kernel_probe_location,
+                       lttng::memory::create_deleter_class<lttng_kernel_probe_location,
+                                                           lttng_kernel_probe_location_destroy>>;
+
+} /* namespace lttng */
+
+#endif /* LTTNG_COMMON_CTL_MEMORY_HPP */
index 6334aaecb133c2af306f13e84ee68fda05d897c1..d7baa1bea7b7c984726540f600cbd2071c14cc72 100644 (file)
@@ -10,6 +10,8 @@
 #include <common/macros.hpp>
 #include <common/make-unique.hpp>
 
+#include <vendor/optional.hpp>
+
 #include <cxxabi.h>
 #include <string>
 #include <utility>
@@ -46,6 +48,22 @@ struct formatter<std::type_info> : formatter<std::string> {
                return it;
        }
 };
+
+template <typename WrappedType>
+struct formatter<nonstd::optional<WrappedType>> : formatter<WrappedType> {
+       template <typename FormatContextType>
+       typename FormatContextType::iterator format(const nonstd::optional<WrappedType>& opt,
+                                                   FormatContextType& ctx) const
+       {
+               if (opt) {
+                       /* Defer formatting to the base formatter for WrappedType. */
+                       return formatter<WrappedType>::format(*opt, ctx);
+               } else {
+                       /* Print "unset" when the optional has no value. */
+                       return format_to(ctx.out(), "unset");
+               }
+       }
+};
 } /* namespace fmt */
 
 namespace lttng {
diff --git a/src/common/math.hpp b/src/common/math.hpp
new file mode 100644 (file)
index 0000000..0a775f7
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_MATH_HPP
+#define LTTNG_MATH_HPP
+
+#include <type_traits>
+
+namespace lttng {
+namespace math {
+template <typename IntegralType>
+bool is_power_of_two(IntegralType value)
+{
+       static_assert(std::is_integral<IntegralType>::value,
+                     "IntegralType must be an integral type.");
+       if (value < 0) {
+               return false;
+       }
+
+       return __builtin_popcount(value) == 1;
+}
+} /* namespace math */
+} /* namespace lttng */
+
+#endif /* LTTNG_MATH_HPP */
index 386ac8fdaab4bea73f2e3e1dfb4db10ee3f1d187..055b5ecb78ac7324ce7fbc9e2076fb86da1c5562 100644 (file)
@@ -79,7 +79,7 @@ public:
         */
        operator bool() const noexcept /* NOLINT(google-explicit-constructor) */
        {
-               return *this->data();
+               return this->data() && *this->data();
        }
 
        /*
@@ -207,6 +207,13 @@ bool operator==(LhsT&& lhs, RhsT&& rhs) noexcept
        const auto raw_lhs = internal::as_const_char_ptr(lhs);
        const auto raw_rhs = internal::as_const_char_ptr(rhs);
 
+       if (raw_lhs == raw_rhs) {
+               return true;
+       } else if (!raw_lhs || !raw_rhs) {
+               /* Only one of the strings is null, not equal. */
+               return false;
+       }
+
        return std::strcmp(raw_lhs, raw_rhs) == 0;
 }
 
index a3c8ce6e0a23a134dcc0c91d6d6ccf1c45d273c5..5700a86b2785ce94dde052e1a79f4cbe2e48268a 100644 (file)
@@ -8,6 +8,8 @@ liblttng_ctl_la_SOURCES = \
                deprecated-symbols.cpp \
                destruction-handle.cpp \
                event.cpp \
+               event-rule-convert.cpp \
+               event-rule-convert.hpp \
                load.cpp \
                lttng-ctl.cpp \
                lttng-ctl-health.cpp \
index 9e5fc409c218f29fd2a54514703c0a5021a7a710..5838ac2bb5c6cf219d73fbc40d53963c0866b946 100644 (file)
@@ -160,8 +160,11 @@ lttng_notification_channel_create(struct lttng_endpoint *endpoint)
        CDS_INIT_LIST_HEAD(&channel->pending_notifications.list);
 
        {
-               const auto length = std::snprintf(
-                       nullptr, 0, DEFAULT_NOTIFICATION_CHANNEL_UNIX_SOCK, rundir_path.get()) + 1;
+               const auto length = std::snprintf(nullptr,
+                                                 0,
+                                                 DEFAULT_NOTIFICATION_CHANNEL_UNIX_SOCK,
+                                                 rundir_path.get()) +
+                       1;
 
                std::vector<char> sock_path;
                sock_path.reserve(length);
diff --git a/src/lib/lttng-ctl/event-rule-convert.cpp b/src/lib/lttng-ctl/event-rule-convert.cpp
new file mode 100644 (file)
index 0000000..a4c5436
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "event-rule-convert.hpp"
+
+#include <common/ctl/format.hpp>
+#include <common/exception.hpp>
+
+using log_level_rule_uptr = std::unique_ptr<
+       lttng_log_level_rule,
+       lttng::memory::create_deleter_class<lttng_log_level_rule, lttng_log_level_rule_destroy>>;
+
+using EventRuleCreateFunctionType = lttng_event_rule *(*) ();
+using EventRuleSetNamePatternFunctionType = lttng_event_rule_status (*)(lttng_event_rule *,
+                                                                       const char *);
+using EventRuleSetLogLevelRuleFunctionType =
+       lttng_event_rule_status (*)(lttng_event_rule *, const lttng_log_level_rule *);
+using EventRuleSetFilterExpressionFunctionType = lttng_event_rule_status (*)(lttng_event_rule *,
+                                                                            const char *);
+
+namespace {
+log_level_rule_uptr create_log_level_rule_from_lttng_event(const lttng_event& event)
+{
+       log_level_rule_uptr rule;
+       lttng_log_level_rule_type log_level_rule_type;
+
+       switch (event.loglevel_type) {
+       case LTTNG_EVENT_LOGLEVEL_ALL:
+               return nullptr;
+       case LTTNG_EVENT_LOGLEVEL_RANGE:
+               rule.reset(lttng_log_level_rule_exactly_create(event.loglevel));
+               log_level_rule_type = LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS;
+               break;
+       case LTTNG_EVENT_LOGLEVEL_SINGLE:
+               rule.reset(lttng_log_level_rule_at_least_as_severe_as_create(event.loglevel));
+               log_level_rule_type = LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY;
+               break;
+       default:
+               LTTNG_THROW_INVALID_ARGUMENT_ERROR(
+                       fmt::format("Invalid log level type: type={}", event.loglevel_type));
+       }
+
+       if (!rule) {
+               LTTNG_THROW_ERROR(
+                       fmt::format("Failed to allocate log level rule: rule_type={}, level={}",
+                                   log_level_rule_type,
+                                   event.loglevel));
+       }
+
+       return rule;
+}
+
+template <EventRuleCreateFunctionType EventRuleCreateFunction,
+         EventRuleSetNamePatternFunctionType EventRuleSetNamePatternFunction,
+         EventRuleSetLogLevelRuleFunctionType EventRuleSetLogLevelRuleFunction,
+         EventRuleSetFilterExpressionFunctionType EventRuleSetFilterExpressionFunction>
+lttng::event_rule_uptr create_user_or_agent_event_rule_from_lttng_event(
+       const lttng_event& event,
+       lttng_domain_type domain,
+       const log_level_rule_uptr& log_level_rule,
+       nonstd::optional<lttng::c_string_view> filter_expression)
+{
+       lttng::event_rule_uptr rule{ EventRuleCreateFunction() };
+
+       if (!rule) {
+               LTTNG_THROW_ERROR(fmt::format("Failed to allocate event rule: domain={}", domain));
+       }
+
+       const auto pattern = event.name[0] == '\0' ? "*" : event.name;
+       const auto set_pattern_ret = EventRuleSetNamePatternFunction(rule.get(), pattern);
+       if (set_pattern_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+               LTTNG_THROW_ERROR(fmt::format(
+                       "Failed to set name pattern on event rule: domain={}, pattern=`{}`",
+                       domain,
+                       pattern));
+       }
+
+       if (log_level_rule) {
+               const auto set_log_level_rule_ret =
+                       EventRuleSetLogLevelRuleFunction(rule.get(), log_level_rule.get());
+               if (set_log_level_rule_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                       if (set_log_level_rule_ret == LTTNG_EVENT_RULE_STATUS_INVALID) {
+                               LTTNG_THROW_CTL("Invalid log level specified for domain",
+                                               LTTNG_ERR_INVALID);
+                       } else {
+                               LTTNG_THROW_ERROR(fmt::format(
+                                       "Failed to set log level rule on event rule: domain=\"{}\"",
+                                       domain));
+                       }
+               }
+       }
+
+       if (filter_expression) {
+               const auto set_filter_expression_ret =
+                       EventRuleSetFilterExpressionFunction(rule.get(), filter_expression->data());
+               if (set_filter_expression_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                       LTTNG_THROW_ERROR(fmt::format(
+                               "Failed to set filter expression on event rule: domain={}, filter_expression=`{}`",
+                               domain,
+                               *filter_expression));
+               }
+       }
+
+       return rule;
+}
+
+lttng::event_rule_uptr
+create_kernel_event_rule_from_lttng_event(const lttng_event& event,
+                                         nonstd::optional<lttng::c_string_view> filter_expression)
+{
+       lttng::event_rule_uptr rule;
+
+       switch (event.type) {
+       case LTTNG_EVENT_ALL:
+               /* Caller should enable all syscalls and all tracepoints explicitly/separately. */
+               LTTNG_THROW_UNSUPPORTED_ERROR(
+                       "'All' instrumentation type is unsupported by the event rule interface");
+       case LTTNG_EVENT_TRACEPOINT:
+       {
+               const auto pattern = event.name[0] == '\0' ? "*" : event.name;
+               rule.reset(lttng_event_rule_kernel_tracepoint_create());
+               if (!rule) {
+                       LTTNG_THROW_ALLOCATION_FAILURE_ERROR(
+                               "Failed to create kernel tracepoint event rule");
+               }
+
+               const auto set_pattern_ret =
+                       lttng_event_rule_kernel_tracepoint_set_name_pattern(rule.get(), pattern);
+               if (set_pattern_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                       LTTNG_THROW_ERROR(fmt::format(
+                               "Failed to set name pattern on kernel tracepoint event rule: pattern=`{}`",
+                               pattern));
+               };
+
+               if (filter_expression) {
+                       const auto set_filter_ret = lttng_event_rule_kernel_tracepoint_set_filter(
+                               rule.get(), filter_expression->data());
+                       if (set_filter_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                               LTTNG_THROW_ERROR(fmt::format(
+                                       "Failed to set filter expression on kernel tracepoint event rule: filter_expression=`{}`",
+                                       filter_expression->data()));
+                       };
+               }
+               break;
+       }
+       case LTTNG_EVENT_PROBE:
+       case LTTNG_EVENT_FUNCTION:
+       {
+               lttng::kernel_location_uptr location;
+
+               if (event.attr.probe.symbol_name[0]) {
+                       /* Specified by name. */
+                       location.reset(lttng_kernel_probe_location_symbol_create(
+                               event.attr.probe.symbol_name, event.attr.probe.offset));
+               } else {
+                       /* Specified by address. */
+                       location.reset(
+                               lttng_kernel_probe_location_address_create(event.attr.probe.addr));
+               }
+
+               if (!location) {
+                       LTTNG_THROW_ERROR(
+                               "Failed to create kernel probe location from lttng_event");
+               }
+
+               rule.reset(lttng_event_rule_kernel_kprobe_create(location.get()));
+               if (!rule) {
+                       LTTNG_THROW_ALLOCATION_FAILURE_ERROR(
+                               "Failed to create kernel kprobe event rule");
+               }
+
+               const auto set_name_ret =
+                       lttng_event_rule_kernel_kprobe_set_event_name(rule.get(), event.name);
+               if (set_name_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                       LTTNG_THROW_ERROR(fmt::format(
+                               "Failed to set name on kernel tracepoint event rule: name=`{}`",
+                               event.name));
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_SYSCALL:
+       {
+               const auto pattern = event.name[0] == '\0' ? "*" : event.name;
+
+               /* Entry + exit is currently the only mode exposed for recording event rules. */
+               rule.reset(lttng_event_rule_kernel_syscall_create(
+                       LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY_EXIT));
+               if (!rule) {
+                       LTTNG_THROW_ALLOCATION_FAILURE_ERROR(
+                               "Failed to create kernel syscall event rule");
+               }
+
+               const auto set_pattern_ret =
+                       lttng_event_rule_kernel_syscall_set_name_pattern(rule.get(), pattern);
+               if (set_pattern_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                       LTTNG_THROW_ERROR(fmt::format(
+                               "Failed to set name pattern on kernel syscall event rule: pattern=`{}`",
+                               pattern));
+               };
+
+               if (filter_expression) {
+                       const auto set_filter_ret = lttng_event_rule_kernel_syscall_set_filter(
+                               rule.get(), filter_expression->data());
+                       if (set_filter_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                               LTTNG_THROW_ERROR(fmt::format(
+                                       "Failed to set filter expression on kernel syscall event rule: filter_expression=`{}`",
+                                       filter_expression->data()));
+                       };
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_USERSPACE_PROBE:
+       {
+               const auto location = lttng_event_get_userspace_probe_location(&event);
+
+               rule.reset(lttng_event_rule_kernel_uprobe_create(location));
+               if (!rule) {
+                       LTTNG_THROW_ALLOCATION_FAILURE_ERROR(
+                               "Failed to create kernel user space probe event rule");
+               }
+
+               const auto set_name_ret =
+                       lttng_event_rule_kernel_uprobe_set_event_name(rule.get(), event.name);
+               if (set_name_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                       LTTNG_THROW_ERROR(fmt::format(
+                               "Failed to set name on kernel uprobe event rule: name=`{}`",
+                               event.name));
+               }
+
+               break;
+       }
+       default:
+               LTTNG_THROW_UNSUPPORTED_ERROR(
+                       "Unsupported instrumentation type encountered while creating kernel event rule from lttng_event");
+       }
+
+       return rule;
+}
+} /* namespace */
+
+lttng::event_rule_uptr lttng::ctl::create_event_rule_from_lttng_event(
+       const lttng_event& event,
+       lttng_domain_type domain,
+       const nonstd::optional<lttng::c_string_view>& filter_expression,
+       const std::vector<lttng::c_string_view>& exclusions)
+{
+       lttng::event_rule_uptr rule;
+       const auto log_level_rule = [&event, domain]() {
+               switch (domain) {
+               case LTTNG_DOMAIN_UST:
+               case LTTNG_DOMAIN_LOG4J:
+               case LTTNG_DOMAIN_LOG4J2:
+               case LTTNG_DOMAIN_JUL:
+               case LTTNG_DOMAIN_PYTHON:
+                       return create_log_level_rule_from_lttng_event(event);
+               default:
+                       return log_level_rule_uptr();
+               }
+       }();
+
+       switch (domain) {
+       case LTTNG_DOMAIN_KERNEL:
+               rule = create_kernel_event_rule_from_lttng_event(event, filter_expression);
+               break;
+       case LTTNG_DOMAIN_UST:
+               rule = create_user_or_agent_event_rule_from_lttng_event<
+                       lttng_event_rule_user_tracepoint_create,
+                       lttng_event_rule_user_tracepoint_set_name_pattern,
+                       lttng_event_rule_user_tracepoint_set_log_level_rule,
+                       lttng_event_rule_user_tracepoint_set_filter>(
+                       event, domain, log_level_rule, filter_expression);
+               break;
+       case LTTNG_DOMAIN_LOG4J:
+               rule = create_user_or_agent_event_rule_from_lttng_event<
+                       lttng_event_rule_log4j_logging_create,
+                       lttng_event_rule_log4j_logging_set_name_pattern,
+                       lttng_event_rule_log4j_logging_set_log_level_rule,
+                       lttng_event_rule_log4j_logging_set_filter>(
+                       event, domain, log_level_rule, filter_expression);
+               break;
+       case LTTNG_DOMAIN_LOG4J2:
+               rule = create_user_or_agent_event_rule_from_lttng_event<
+                       lttng_event_rule_log4j2_logging_create,
+                       lttng_event_rule_log4j2_logging_set_name_pattern,
+                       lttng_event_rule_log4j2_logging_set_log_level_rule,
+                       lttng_event_rule_log4j2_logging_set_filter>(
+                       event, domain, log_level_rule, filter_expression);
+               break;
+       case LTTNG_DOMAIN_JUL:
+               rule = create_user_or_agent_event_rule_from_lttng_event<
+                       lttng_event_rule_jul_logging_create,
+                       lttng_event_rule_jul_logging_set_name_pattern,
+                       lttng_event_rule_jul_logging_set_log_level_rule,
+                       lttng_event_rule_jul_logging_set_filter>(
+                       event, domain, log_level_rule, filter_expression);
+               break;
+       case LTTNG_DOMAIN_PYTHON:
+               rule = create_user_or_agent_event_rule_from_lttng_event<
+                       lttng_event_rule_python_logging_create,
+                       lttng_event_rule_python_logging_set_name_pattern,
+                       lttng_event_rule_python_logging_set_log_level_rule,
+                       lttng_event_rule_python_logging_set_filter>(
+                       event, domain, log_level_rule, filter_expression);
+               break;
+       default:
+               LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+                       "Invalid domain specified during event-rule creation: domain={}", domain));
+       }
+
+       if (!exclusions.empty()) {
+               if (domain != LTTNG_DOMAIN_UST) {
+                       LTTNG_THROW_UNSUPPORTED_ERROR(
+                               "Pattern exclusions are only supported by the user space domain");
+               }
+
+               for (const auto& exclusion : exclusions) {
+                       const auto set_exclusions_ret =
+                               lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
+                                       rule.get(), exclusion.data());
+
+                       if (set_exclusions_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+                               LTTNG_THROW_ERROR(fmt::format(
+                                       "Failed to add name pattern exclusion to event rule: pattern=`{}`",
+                                       exclusion));
+                       }
+               }
+       }
+
+       return rule;
+}
diff --git a/src/lib/lttng-ctl/event-rule-convert.hpp b/src/lib/lttng-ctl/event-rule-convert.hpp
new file mode 100644 (file)
index 0000000..151fde4
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_CTL_EVENT_RULE_CONVERT_HPP
+#define LTTNG_CTL_EVENT_RULE_CONVERT_HPP
+
+#include "lttng/event-rule/event-rule-internal.hpp"
+
+#include <common/ctl/memory.hpp>
+#include <common/string-utils/c-string-view.hpp>
+
+#include <lttng/lttng.h>
+
+#include <vendor/optional.hpp>
+
+#include <memory>
+#include <vector>
+
+namespace lttng {
+namespace ctl {
+event_rule_uptr
+create_event_rule_from_lttng_event(const lttng_event& event,
+                                  lttng_domain_type domain,
+                                  const nonstd::optional<lttng::c_string_view>& filter_expression,
+                                  const std::vector<lttng::c_string_view>& exclusions);
+} /* namespace ctl */
+} /* namespace lttng */
+
+#endif /* LTTNG_CTL_EVENT_RULE_CONVERT_HPP */
index 73bfd0db7ca17fcb72667f5c9d8366713497a888..cb2070c8221e11b054e87e50c7027c3418b3e273 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #define _LGPL_SOURCE
+#include "event-rule-convert.hpp"
 #include "lttng-ctl-helper.hpp"
 
 #include <common/align.hpp>
 #include <common/defaults.hpp>
 #include <common/dynamic-array.hpp>
 #include <common/dynamic-buffer.hpp>
+#include <common/exception.hpp>
 #include <common/filter/filter-ast.hpp>
+/* NOLINTNEXTLINE */
 #include <common/filter/filter-parser.hpp>
 #include <common/filter/memstream.hpp>
 #include <common/make-unique-wrapper.hpp>
 #include <common/payload-view.hpp>
 #include <common/payload.hpp>
+#include <common/scope-exit.hpp>
 #include <common/sessiond-comm/sessiond-comm.hpp>
 #include <common/tracker.hpp>
 #include <common/unix.hpp>
@@ -1020,77 +1024,74 @@ int lttng_enable_event_with_filter(struct lttng_handle *handle,
 }
 
 /*
- * Depending on the event, return a newly allocated agent filter expression or
- * NULL if not applicable.
+ * Depending on the event, return a new agent filter expression or
+ * an empty string if not applicable.
  *
- * An event with NO loglevel and the name is * will return NULL.
+ * An event with NO loglevel and the name is * will return an empty string.
  */
-static char *
-set_agent_filter(const char *filter, struct lttng_event *ev, struct lttng_domain *domain)
+static std::string build_agent_filter_expression(const char *original_filter_expression,
+                                                const lttng_event& ev,
+                                                const lttng_domain& domain)
 {
-       int err;
-       char *agent_filter = nullptr;
+       std::string agent_filter;
 
-       LTTNG_ASSERT(ev);
-       LTTNG_ASSERT(domain);
+       try {
+               /* Don't add filter for the '*' event. */
+               std::string logger_name_filter;
 
-       /* Don't add filter for the '*' event. */
-       if (strcmp(ev->name, "*") != 0) {
-               if (filter) {
-                       err = asprintf(
-                               &agent_filter, "(%s) && (logger_name == \"%s\")", filter, ev->name);
-               } else {
-                       err = asprintf(&agent_filter, "logger_name == \"%s\"", ev->name);
+               if (lttng::c_string_view(ev.name) != "*" &&
+                   lttng::c_string_view(ev.name).len() != 0) {
+                       logger_name_filter = fmt::format("logger_name == \"{}\"", ev.name);
                }
-               if (err < 0) {
-                       PERROR("asprintf");
-                       goto error;
+
+               if (original_filter_expression == nullptr) {
+                       agent_filter = std::move(logger_name_filter);
+               } else {
+                       if (logger_name_filter.size() > 0) {
+                               agent_filter = fmt::format("({}) && ({})",
+                                                          original_filter_expression,
+                                                          logger_name_filter);
+                       } else {
+                               agent_filter.append(original_filter_expression);
+                       }
                }
-       }
 
-       /* Add loglevel filtering if any for the agent domains. */
-       if (ev->loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
-               const char *op;
+               /* Add loglevel filtering if any for the agent domains. */
+               if (ev.loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
+                       std::string op;
 
-               if (ev->loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) {
-                       /*
-                        * Log4j2 is the only agent domain for which more severe
-                        * logging levels have a lower numerical value.
-                        */
-                       if (domain->type == LTTNG_DOMAIN_LOG4J2) {
-                               op = "<=";
+                       if (ev.loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) {
+                               /*
+                                * Log4j2 is the only agent domain for which more severe logging
+                                * levels have a lower numerical value.
+                                */
+                               if (domain.type == LTTNG_DOMAIN_LOG4J2) {
+                                       op = "<=";
+                               } else {
+                                       op = ">=";
+                               }
                        } else {
-                               op = ">=";
+                               op = "==";
                        }
-               } else {
-                       op = "==";
-               }
 
-               if (filter || agent_filter) {
-                       char *new_filter;
+                       if (original_filter_expression != nullptr || !agent_filter.empty()) {
+                               std::string existing_filter = !agent_filter.empty() ?
+                                       agent_filter :
+                                       std::string(original_filter_expression);
 
-                       err = asprintf(&new_filter,
-                                      "(%s) && (int_loglevel %s %d)",
-                                      agent_filter ? agent_filter : filter,
-                                      op,
-                                      ev->loglevel);
-                       if (agent_filter) {
-                               free(agent_filter);
+                               agent_filter = fmt::format("({}) && (int_loglevel {} {})",
+                                                          existing_filter,
+                                                          op,
+                                                          ev.loglevel);
+                       } else {
+                               agent_filter = fmt::format("int_loglevel {} {}", op, ev.loglevel);
                        }
-                       agent_filter = new_filter;
-               } else {
-                       err = asprintf(&agent_filter, "int_loglevel %s %d", op, ev->loglevel);
-               }
-               if (err < 0) {
-                       PERROR("asprintf");
-                       goto error;
                }
+       } catch (const std::exception& e) {
+               return std::string();
        }
 
        return agent_filter;
-error:
-       free(agent_filter);
-       return nullptr;
 }
 
 /*
@@ -1108,35 +1109,48 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
                                       int exclusion_count,
                                       char **exclusion_list)
 {
-       struct lttcomm_session_msg lsm = {
+       lttcomm_session_msg lsm = {
                .cmd_type = LTTCOMM_SESSIOND_COMMAND_ENABLE_EVENT,
                .session = {},
                .domain = {},
                .u = {},
                .fd_count = 0,
        };
-       struct lttng_payload payload;
+       lttng_payload payload;
        int ret = 0;
-       unsigned int free_filter_expression = 0;
-       struct filter_parser_ctx *ctx = nullptr;
-       size_t bytecode_len = 0;
 
-       /*
-        * We have either a filter or some exclusions, so we need to set up
-        * a variable-length payload from where to send the data.
-        */
-       lttng_payload_init(&payload);
-
-       /*
-        * Cast as non-const since we may replace the filter expression
-        * by a dynamically allocated string. Otherwise, the original
-        * string is not modified.
-        */
-       char *filter_expression = (char *) original_filter_expression;
+       if (ev->type == LTTNG_EVENT_ALL) {
+               /*
+                * Since we modify the user's parameter, ensure it is set back to its original value
+                * on exit.
+                */
+               const auto restore_event_type_value =
+                       lttng::make_scope_exit([&ev]() noexcept { ev->type = LTTNG_EVENT_ALL; });
+
+               ev->type = LTTNG_EVENT_TRACEPOINT;
+               const auto tp_ret = lttng_enable_event_with_exclusions(handle,
+                                                                      ev,
+                                                                      channel_name,
+                                                                      original_filter_expression,
+                                                                      exclusion_count,
+                                                                      exclusion_list);
+               if (tp_ret < 0 || handle->domain.type != LTTNG_DOMAIN_KERNEL) {
+                       return tp_ret;
+               }
+
+               ev->type = LTTNG_EVENT_SYSCALL;
+               const auto syscall_ret =
+                       lttng_enable_event_with_exclusions(handle,
+                                                          ev,
+                                                          channel_name,
+                                                          original_filter_expression,
+                                                          exclusion_count,
+                                                          exclusion_list);
+               return syscall_ret;
+       }
 
        if (handle == nullptr || ev == nullptr) {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+               return -LTTNG_ERR_INVALID;
        }
 
        /*
@@ -1144,85 +1158,150 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
         * anyway, so treat this corner-case early to eliminate
         * lttng_fmemopen error for 0-byte allocation.
         */
-       if (filter_expression && filter_expression[0] == '\0') {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+       if (original_filter_expression && strlen(original_filter_expression) == 0) {
+               return -LTTNG_ERR_INVALID;
        }
 
+       /*
+        * We have either a filter or some exclusions, so we need to set up
+        * a variable-length payload from where to send the data.
+        */
+       lttng_payload_init(&payload);
+       /* Clean-up payload when returning. */
+       auto cleanup_payload =
+               lttng::make_scope_exit([&payload]() noexcept { lttng_payload_reset(&payload); });
+
+       /* The filter expression may be modified below in the case of agent domains. */
+       std::string filter_expression(original_filter_expression ?: "");
+
        if (ev->name[0] == '\0') {
                /* Enable all events. */
                ret = lttng_strncpy(ev->name, "*", sizeof(ev->name));
                LTTNG_ASSERT(ret == 0);
        }
 
-       /* Parse filter expression. */
-       if (filter_expression != nullptr || handle->domain.type == LTTNG_DOMAIN_JUL ||
-           handle->domain.type == LTTNG_DOMAIN_LOG4J ||
+       if (handle->domain.type == LTTNG_DOMAIN_JUL || handle->domain.type == LTTNG_DOMAIN_LOG4J ||
            handle->domain.type == LTTNG_DOMAIN_LOG4J2 ||
            handle->domain.type == LTTNG_DOMAIN_PYTHON) {
-               if (handle->domain.type == LTTNG_DOMAIN_JUL ||
-                   handle->domain.type == LTTNG_DOMAIN_LOG4J ||
-                   handle->domain.type == LTTNG_DOMAIN_LOG4J2 ||
-                   handle->domain.type == LTTNG_DOMAIN_PYTHON) {
-                       char *agent_filter;
-
-                       /* Setup agent filter if needed. */
-                       agent_filter = set_agent_filter(filter_expression, ev, &handle->domain);
-                       if (!agent_filter) {
-                               if (!filter_expression) {
-                                       /*
-                                        * No agent and no filter, just skip
-                                        * everything below.
-                                        */
-                                       goto serialize;
-                               }
-                       } else {
-                               /*
-                                * With an agent filter, the original filter has
-                                * been added to it thus replace the filter
-                                * expression.
-                                */
-                               filter_expression = agent_filter;
-                               free_filter_expression = 1;
-                       }
+               /* Setup agent filter if needed. */
+               try {
+                       filter_expression = build_agent_filter_expression(
+                               original_filter_expression, *ev, handle->domain);
+               } catch (const std::bad_alloc& bad_alloc_ex) {
+                       return -LTTNG_ERR_NOMEM;
+               } catch (...) {
+                       return -LTTNG_ERR_UNK;
                }
+       }
 
-               if (strnlen(filter_expression, LTTNG_FILTER_MAX_LEN) == LTTNG_FILTER_MAX_LEN) {
-                       ret = -LTTNG_ERR_FILTER_INVAL;
-                       goto error;
+       if (handle->domain.type == LTTNG_DOMAIN_KERNEL && ev->type == LTTNG_EVENT_ALL) {
+               /*
+                * Syscall and tracepoints are different instrumentation types that must be
+                * enabled by separate event rules.
+                */
+               ev->type = LTTNG_EVENT_SYSCALL;
+               ret = lttng_enable_event_with_exclusions(handle,
+                                                        ev,
+                                                        channel_name,
+                                                        original_filter_expression,
+                                                        exclusion_count,
+                                                        exclusion_list);
+               if (ret < 0) {
+                       return ret;
+               }
+
+               ev->type = LTTNG_EVENT_TRACEPOINT;
+               ret = lttng_enable_event_with_exclusions(handle,
+                                                        ev,
+                                                        channel_name,
+                                                        original_filter_expression,
+                                                        exclusion_count,
+                                                        exclusion_list);
+               if (ret < 0) {
+                       return ret;
                }
 
-               ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
+               return ret;
+       }
+
+       std::vector<lttng::c_string_view> exclusions_vec;
+       if (exclusion_count > 0) {
+               exclusions_vec.reserve(exclusion_count);
+
+               for (unsigned int i = 0; i < exclusion_count; i++) {
+                       exclusions_vec.emplace_back(exclusion_list[i]);
+               }
+       }
+
+       lttng::event_rule_uptr event_rule;
+       try {
+               event_rule = lttng::ctl::create_event_rule_from_lttng_event(
+                       *ev,
+                       handle->domain.type,
+                       original_filter_expression ?
+                               nonstd::make_optional(original_filter_expression) :
+                               nonstd::nullopt,
+                       exclusions_vec);
+       } catch (const lttng::ctl::error& ctl_error) {
+               DBG("%s", ctl_error.what());
+               return -LTTNG_ERR_INVALID;
+       } catch (const std::exception& ex) {
+               DBG("%s", ex.what());
+               return -LTTNG_ERR_UNK;
+       }
+
+       filter_parser_ctx *ctx = nullptr;
+
+       if (filter_expression.size() > 0) {
+               ret = filter_parser_ctx_create_from_filter_expression(filter_expression.c_str(),
+                                                                     &ctx);
                if (ret) {
-                       goto error;
+                       return -LTTNG_ERR_INVALID;
                }
+       }
 
-               bytecode_len = bytecode_get_len(&ctx->bytecode->b) + sizeof(ctx->bytecode->b);
-               if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
-                       ret = -LTTNG_ERR_FILTER_INVAL;
-                       goto error;
+       const auto free_bytecode_ir_and_parser_context = lttng::make_scope_exit([ctx]() noexcept {
+               if (!ctx) {
+                       return;
                }
+
+               filter_bytecode_free(ctx);
+               filter_ir_free(ctx);
+               filter_parser_ctx_free(ctx);
+       });
+
+       const auto bytecode_len =
+               ctx ? (bytecode_get_len(&ctx->bytecode->b) + sizeof(ctx->bytecode->b)) : 0;
+       if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
+               return -LTTNG_ERR_INVALID;
        }
 
-serialize:
        ret = lttng_event_serialize(ev,
                                    exclusion_count,
                                    exclusion_list,
-                                   filter_expression,
+                                   filter_expression.size() > 0 ? filter_expression.c_str() :
+                                                                  nullptr,
                                    bytecode_len,
                                    (ctx && bytecode_len) ? &ctx->bytecode->b : nullptr,
                                    &payload);
        if (ret) {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+               return -LTTNG_ERR_INVALID;
+       }
+
+       if (!lttng_event_rule_validate(event_rule.get())) {
+               return -LTTNG_ERR_INVALID;
+       }
+
+       ret = lttng_event_rule_serialize(event_rule.get(), &payload);
+       if (ret) {
+               return -LTTNG_ERR_INVALID;
        }
 
        /* If no channel name, send empty string. */
        ret = lttng_strncpy(
                lsm.u.enable.channel_name, channel_name ?: "", sizeof(lsm.u.enable.channel_name));
        if (ret) {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+               return -LTTNG_ERR_INVALID;
        }
 
        /* Domain */
@@ -1231,67 +1310,46 @@ serialize:
        /* Session name */
        ret = lttng_strncpy(lsm.session.name, handle->session_name, sizeof(lsm.session.name));
        if (ret) {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+               return -LTTNG_ERR_INVALID;
        }
 
-       /* Length of the serialized event. */
+       /* Length of the serialized event rule. */
        lsm.u.enable.length = (uint32_t) payload.buffer.size;
 
-       {
-               struct lttng_payload_view view = lttng_payload_view_from_payload(&payload, 0, -1);
-               const int fd_count = lttng_payload_view_get_fd_handle_count(&view);
-               int fd_to_send;
+       lttng_payload_view view = lttng_payload_view_from_payload(&payload, 0, -1);
+       const auto fd_count = lttng_payload_view_get_fd_handle_count(&view);
 
-               if (fd_count < 0) {
-                       goto error;
-               }
+       if (fd_count < 0) {
+               return -LTTNG_ERR_UNK;
+       }
 
-               LTTNG_ASSERT(fd_count == 0 || fd_count == 1);
-               if (fd_count == 1) {
-                       struct fd_handle *h = lttng_payload_view_pop_fd_handle(&view);
+       LTTNG_ASSERT(fd_count == 0 || fd_count == 2);
 
-                       if (!h) {
-                               goto error;
-                       }
+       std::vector<int> fds_to_send;
 
-                       fd_to_send = fd_handle_get_fd(h);
-                       fd_handle_put(h);
-               }
+       fds_to_send.reserve(fd_count);
+       for (auto i = 0; i < fd_count; i++) {
+               fd_handle *h = lttng_payload_view_pop_fd_handle(&view);
 
-               lsm.fd_count = fd_count;
+               if (!h) {
+                       return -LTTNG_ERR_UNK;
+               }
 
-               ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm,
-                                                       fd_count ? &fd_to_send : nullptr,
-                                                       fd_count,
-                                                       view.buffer.size ? view.buffer.data :
-                                                                          nullptr,
-                                                       view.buffer.size,
-                                                       nullptr,
-                                                       nullptr,
-                                                       nullptr);
+               const auto fd_to_send = fd_handle_get_fd(h);
+               fds_to_send.push_back(fd_to_send);
+               fd_handle_put(h);
        }
 
-error:
-       if (filter_expression && ctx) {
-               filter_bytecode_free(ctx);
-               filter_ir_free(ctx);
-               filter_parser_ctx_free(ctx);
-       }
-       if (free_filter_expression) {
-               /*
-                * The filter expression has been replaced and must be freed as
-                * it is not the original filter expression received as a
-                * parameter.
-                */
-               free(filter_expression);
-       }
-       /*
-        * Return directly to the caller and don't ask the sessiond since
-        * something went wrong in the parsing of data above.
-        */
-       lttng_payload_reset(&payload);
-       return ret;
+       lsm.fd_count = fd_count;
+
+       return lttng_ctl_ask_sessiond_fds_varlen(&lsm,
+                                                fd_count ? fds_to_send.data() : nullptr,
+                                                fd_count,
+                                                view.buffer.size ? view.buffer.data : nullptr,
+                                                view.buffer.size,
+                                                nullptr,
+                                                nullptr,
+                                                nullptr);
 }
 
 int lttng_disable_event_ext(struct lttng_handle *handle,
@@ -1299,35 +1357,18 @@ int lttng_disable_event_ext(struct lttng_handle *handle,
                            const char *channel_name,
                            const char *original_filter_expression)
 {
-       struct lttcomm_session_msg lsm = {
+       lttcomm_session_msg lsm = {
                .cmd_type = LTTCOMM_SESSIOND_COMMAND_DISABLE_EVENT,
                .session = {},
                .domain = {},
                .u = {},
                .fd_count = 0,
        };
-       struct lttng_payload payload;
+       lttng_payload payload;
        int ret = 0;
-       unsigned int free_filter_expression = 0;
-       struct filter_parser_ctx *ctx = nullptr;
-       size_t bytecode_len = 0;
-
-       /*
-        * We have either a filter or some exclusions, so we need to set up
-        * a variable-length payload from where to send the data.
-        */
-       lttng_payload_init(&payload);
-
-       /*
-        * Cast as non-const since we may replace the filter expression
-        * by a dynamically allocated string. Otherwise, the original
-        * string is not modified.
-        */
-       char *filter_expression = (char *) original_filter_expression;
 
        if (handle == nullptr || ev == nullptr) {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+               return -LTTNG_ERR_INVALID;
        }
 
        /*
@@ -1335,79 +1376,105 @@ int lttng_disable_event_ext(struct lttng_handle *handle,
         * anyway, so treat this corner-case early to eliminate
         * lttng_fmemopen error for 0-byte allocation.
         */
-       if (filter_expression && filter_expression[0] == '\0') {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+       if (original_filter_expression && strlen(original_filter_expression) == 0) {
+               return -LTTNG_ERR_INVALID;
        }
 
-       /* Parse filter expression. */
-       if (filter_expression != nullptr || handle->domain.type == LTTNG_DOMAIN_JUL ||
-           handle->domain.type == LTTNG_DOMAIN_LOG4J ||
+       /*
+        * We have either a filter or some exclusions, so we need to set up
+        * a variable-length payload from where to send the data.
+        */
+       lttng_payload_init(&payload);
+       /* Clean-up payload when returning. */
+       auto cleanup_payload =
+               lttng::make_scope_exit([&payload]() noexcept { lttng_payload_reset(&payload); });
+
+       /* The filter expression may be modified below in the case of agent domains. */
+       std::string filter_expression(original_filter_expression ?: "");
+
+       if (handle->domain.type == LTTNG_DOMAIN_JUL || handle->domain.type == LTTNG_DOMAIN_LOG4J ||
            handle->domain.type == LTTNG_DOMAIN_LOG4J2 ||
            handle->domain.type == LTTNG_DOMAIN_PYTHON) {
-               if (handle->domain.type == LTTNG_DOMAIN_JUL ||
-                   handle->domain.type == LTTNG_DOMAIN_LOG4J ||
-                   handle->domain.type == LTTNG_DOMAIN_LOG4J2 ||
-                   handle->domain.type == LTTNG_DOMAIN_PYTHON) {
-                       char *agent_filter;
-
-                       /* Setup agent filter if needed. */
-                       agent_filter = set_agent_filter(filter_expression, ev, &handle->domain);
-                       if (!agent_filter) {
-                               if (!filter_expression) {
-                                       /*
-                                        * No JUL and no filter, just skip
-                                        * everything below.
-                                        */
-                                       goto serialize;
-                               }
-                       } else {
-                               /*
-                                * With an agent filter, the original filter has
-                                * been added to it thus replace the filter
-                                * expression.
-                                */
-                               filter_expression = agent_filter;
-                               free_filter_expression = 1;
-                       }
+               /* Setup agent filter if needed. */
+               try {
+                       filter_expression = build_agent_filter_expression(
+                               original_filter_expression, *ev, handle->domain);
+               } catch (const std::bad_alloc& bad_alloc_ex) {
+                       return -LTTNG_ERR_NOMEM;
+               } catch (...) {
+                       return -LTTNG_ERR_UNK;
+               }
+       }
+
+       const std::vector<lttng::c_string_view> exclusions_vec;
+       lttng::event_rule_uptr event_rule;
+       if (ev->type != LTTNG_EVENT_ALL) {
+               try {
+                       event_rule = lttng::ctl::create_event_rule_from_lttng_event(
+                               *ev,
+                               handle->domain.type,
+                               original_filter_expression ?
+                                       nonstd::make_optional(original_filter_expression) :
+                                       nonstd::nullopt,
+                               exclusions_vec);
+               } catch (const lttng::ctl::error& ctl_error) {
+                       DBG("%s", ctl_error.what());
+                       return -LTTNG_ERR_INVALID;
+               } catch (const std::exception& ex) {
+                       DBG("%s", ex.what());
+                       return -LTTNG_ERR_UNK;
+               }
+       }
+
+       filter_parser_ctx *ctx = nullptr;
+       if (filter_expression.size() > 0) {
+               ret = filter_parser_ctx_create_from_filter_expression(filter_expression.c_str(),
+                                                                     &ctx);
+               if (ret) {
+                       return -LTTNG_ERR_INVALID;
                }
+       }
 
-               if (strnlen(filter_expression, LTTNG_FILTER_MAX_LEN) == LTTNG_FILTER_MAX_LEN) {
-                       ret = -LTTNG_ERR_FILTER_INVAL;
-                       goto error;
+       const auto free_bytecode_ir_and_parser_context = lttng::make_scope_exit([ctx]() noexcept {
+               if (!ctx) {
+                       return;
                }
 
-               ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
-               if (ret) {
-                       goto error;
-               }
+               filter_bytecode_free(ctx);
+               filter_ir_free(ctx);
+               filter_parser_ctx_free(ctx);
+       });
 
-               bytecode_len = bytecode_get_len(&ctx->bytecode->b) + sizeof(ctx->bytecode->b);
-               if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
-                       ret = -LTTNG_ERR_FILTER_INVAL;
-                       goto error;
-               }
+       const auto bytecode_len =
+               ctx ? (bytecode_get_len(&ctx->bytecode->b) + sizeof(ctx->bytecode->b)) : 0;
+       if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
+               return -LTTNG_ERR_INVALID;
        }
 
-serialize:
        ret = lttng_event_serialize(ev,
                                    0,
                                    nullptr,
-                                   filter_expression,
+                                   filter_expression.size() > 0 ? filter_expression.c_str() :
+                                                                  nullptr,
                                    bytecode_len,
                                    (ctx && bytecode_len) ? &ctx->bytecode->b : nullptr,
                                    &payload);
        if (ret) {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+               return -LTTNG_ERR_INVALID;
+       }
+
+       if (event_rule) {
+               ret = lttng_event_rule_serialize(event_rule.get(), &payload);
+               if (ret) {
+                       return -LTTNG_ERR_INVALID;
+               }
        }
 
        /* If no channel name, send empty string. */
        ret = lttng_strncpy(
                lsm.u.disable.channel_name, channel_name ?: "", sizeof(lsm.u.disable.channel_name));
        if (ret) {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+               return -LTTNG_ERR_INVALID;
        }
 
        /* Domain */
@@ -1416,65 +1483,46 @@ serialize:
        /* Session name */
        ret = lttng_strncpy(lsm.session.name, handle->session_name, sizeof(lsm.session.name));
        if (ret) {
-               ret = -LTTNG_ERR_INVALID;
-               goto error;
+               return -LTTNG_ERR_INVALID;
        }
 
-       /* Length of the serialized event. */
+       /* Length of the serialized event rule. */
        lsm.u.disable.length = (uint32_t) payload.buffer.size;
 
-       {
-               struct lttng_payload_view view = lttng_payload_view_from_payload(&payload, 0, -1);
-               const int fd_count = lttng_payload_view_get_fd_handle_count(&view);
-               int fd_to_send;
+       lttng_payload_view view = lttng_payload_view_from_payload(&payload, 0, -1);
+       const auto fd_count = lttng_payload_view_get_fd_handle_count(&view);
 
-               if (fd_count < 0) {
-                       goto error;
-               }
+       if (fd_count < 0) {
+               return -LTTNG_ERR_UNK;
+       }
 
-               LTTNG_ASSERT(fd_count == 0 || fd_count == 1);
-               if (fd_count == 1) {
-                       struct fd_handle *h = lttng_payload_view_pop_fd_handle(&view);
+       LTTNG_ASSERT(fd_count == 0 || fd_count == 2);
 
-                       if (!h) {
-                               goto error;
-                       }
+       std::vector<int> fds_to_send;
 
-                       fd_to_send = fd_handle_get_fd(h);
-                       fd_handle_put(h);
+       fds_to_send.reserve(fd_count);
+       for (auto i = 0; i < fd_count; i++) {
+               fd_handle *h = lttng_payload_view_pop_fd_handle(&view);
+
+               if (!h) {
+                       return -LTTNG_ERR_UNK;
                }
 
-               ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm,
-                                                       fd_count ? &fd_to_send : nullptr,
-                                                       fd_count,
-                                                       view.buffer.size ? view.buffer.data :
-                                                                          nullptr,
-                                                       view.buffer.size,
-                                                       nullptr,
-                                                       nullptr,
-                                                       nullptr);
+               const auto fd_to_send = fd_handle_get_fd(h);
+               fds_to_send.push_back(fd_to_send);
+               fd_handle_put(h);
        }
 
-error:
-       if (filter_expression && ctx) {
-               filter_bytecode_free(ctx);
-               filter_ir_free(ctx);
-               filter_parser_ctx_free(ctx);
-       }
-       if (free_filter_expression) {
-               /*
-                * The filter expression has been replaced and must be freed as
-                * it is not the original filter expression received as a
-                * parameter.
-                */
-               free(filter_expression);
-       }
-       /*
-        * Return directly to the caller and don't ask the sessiond since
-        * something went wrong in the parsing of data above.
-        */
-       lttng_payload_reset(&payload);
-       return ret;
+       lsm.fd_count = fd_count;
+
+       return lttng_ctl_ask_sessiond_fds_varlen(&lsm,
+                                                fd_count ? fds_to_send.data() : nullptr,
+                                                fd_count,
+                                                view.buffer.size ? view.buffer.data : nullptr,
+                                                view.buffer.size,
+                                                nullptr,
+                                                nullptr,
+                                                nullptr);
 }
 
 /*
@@ -2663,7 +2711,7 @@ end:
        return ret;
 }
 
-int lttng_channel_get_monitor_timer_interval(struct lttng_channel *chan,
+int lttng_channel_get_monitor_timer_interval(const struct lttng_channel *chan,
                                             uint64_t *monitor_timer_interval)
 {
        int ret = 0;
@@ -2700,7 +2748,7 @@ end:
        return ret;
 }
 
-int lttng_channel_get_blocking_timeout(struct lttng_channel *chan, int64_t *blocking_timeout)
+int lttng_channel_get_blocking_timeout(const struct lttng_channel *chan, int64_t *blocking_timeout)
 {
        int ret = 0;
 
index 4f6041f62d3ec11ce34eac732863b1403f7c7846..4cd21154845be554011cf491d351b7dd500e2e82 100644 (file)
@@ -72,7 +72,7 @@
                                                                <enabled>false</enabled>
                                                                <type>TRACEPOINT</type>
                                                                <loglevel_type>RANGE</loglevel_type>
-                                                               <loglevel>-1</loglevel>
+                                                               <loglevel>5</loglevel>
                                                        </event>
                                                        <event>
                                                                <name>uevent_disabled</name>
This page took 0.08259 seconds and 4 git commands to generate.