Fix: do not flag consumer as disabled on relayd comm failure
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index 325ffd2cf14f6ec3e320e402e8db17a6dac71adc..1edcffe79ce13552d688638162068f8085016a1a 100644 (file)
 #include <common/utils.h>
 #include <common/compat/string.h>
 #include <common/kernel-ctl/kernel-ctl.h>
+#include <common/dynamic-buffer.h>
+#include <common/buffer-view.h>
+#include <lttng/trigger/trigger-internal.h>
+#include <lttng/condition/condition.h>
+#include <lttng/action/action.h>
+#include <lttng/channel.h>
+#include <lttng/channel-internal.h>
+#include <common/string-utils/string-utils.h>
 
 #include "channel.h"
 #include "consumer.h"
@@ -41,6 +49,8 @@
 #include "syscall.h"
 #include "agent.h"
 #include "buffer-registry.h"
+#include "notification-thread.h"
+#include "notification-thread-commands.h"
 
 #include "cmd.h"
 
@@ -53,7 +63,6 @@
 static pthread_mutex_t relayd_net_seq_idx_lock = PTHREAD_MUTEX_INITIALIZER;
 static uint64_t relayd_net_seq_idx;
 
-static int validate_event_name(const char *);
 static int validate_ust_event_name(const char *);
 static int cmd_enable_event_internal(struct ltt_session *session,
                struct lttng_domain *domain,
@@ -235,11 +244,11 @@ end:
 /*
  * Fill lttng_channel array of all channels.
  */
-static void list_lttng_channels(enum lttng_domain_type domain,
+static ssize_t list_lttng_channels(enum lttng_domain_type domain,
                struct ltt_session *session, struct lttng_channel *channels,
-               struct lttcomm_channel_extended *chan_exts)
+               struct lttng_channel_extended *chan_exts)
 {
-       int i = 0, ret;
+       int i = 0, ret = 0;
        struct ltt_kernel_channel *kchan;
 
        DBG("Listing channels for session %s", session->name);
@@ -251,6 +260,10 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                        cds_list_for_each_entry(kchan,
                                        &session->kernel_session->channel_list.head, list) {
                                uint64_t discarded_events, lost_packets;
+                               struct lttng_channel_extended *extended;
+
+                               extended = (struct lttng_channel_extended *)
+                                               kchan->channel->attr.extended.ptr;
 
                                ret = get_kernel_runtime_stats(session, kchan,
                                                &discarded_events, &lost_packets);
@@ -263,6 +276,9 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                                chan_exts[i].discarded_events =
                                                discarded_events;
                                chan_exts[i].lost_packets = lost_packets;
+                               chan_exts[i].monitor_timer_interval =
+                                               extended->monitor_timer_interval;
+                               chan_exts[i].blocking_timeout = 0;
                                i++;
                        }
                }
@@ -308,6 +324,11 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                                break;
                        }
 
+                       chan_exts[i].monitor_timer_interval =
+                                       uchan->monitor_timer_interval;
+                       chan_exts[i].blocking_timeout =
+                               uchan->attr.u.s.blocking_timeout;
+
                        ret = get_ust_runtime_stats(session, uchan,
                                        &discarded_events, &lost_packets);
                        if (ret < 0) {
@@ -325,7 +346,11 @@ static void list_lttng_channels(enum lttng_domain_type domain,
        }
 
 end:
-       return;
+       if (ret < 0) {
+               return -LTTNG_ERR_FATAL;
+       } else {
+               return LTTNG_OK;
+       }
 }
 
 static void increment_extended_len(const char *filter_expression,
@@ -895,7 +920,7 @@ static int send_consumer_relayd_socket(enum lttng_domain_type domain,
        /* Connect to relayd and make version check if uri is the control. */
        ret = create_connect_relayd(relayd_uri, &rsock, consumer);
        if (ret != LTTNG_OK) {
-               goto error;
+               goto relayd_comm_error;
        }
        assert(rsock);
 
@@ -935,10 +960,6 @@ static int send_consumer_relayd_socket(enum lttng_domain_type domain,
         */
 
 close_sock:
-       (void) relayd_close(rsock);
-       free(rsock);
-
-error:
        if (ret != LTTNG_OK) {
                /*
                 * The consumer output for this session should not be used anymore
@@ -947,6 +968,10 @@ error:
                 */
                consumer->enabled = 0;
        }
+       (void) relayd_close(rsock);
+       free(rsock);
+
+relayd_comm_error:
        return ret;
 }
 
@@ -1333,6 +1358,30 @@ int cmd_enable_channel(struct ltt_session *session,
                attr->attr.switch_timer_interval = 0;
        }
 
+       /* Check for feature support */
+       switch (domain->type) {
+       case LTTNG_DOMAIN_KERNEL:
+       {
+               if (kernel_supports_ring_buffer_snapshot_sample_positions(kernel_tracer_fd) != 1) {
+                       /* Sampling position of buffer is not supported */
+                       WARN("Kernel tracer does not support buffer monitoring. "
+                                       "Setting the monitor interval timer to 0 "
+                                       "(disabled) for channel '%s' of session '%s'",
+                                       attr-> name, session->name);
+                       lttng_channel_set_monitor_timer_interval(attr, 0);
+               }
+               break;
+       }
+       case LTTNG_DOMAIN_UST:
+       case LTTNG_DOMAIN_JUL:
+       case LTTNG_DOMAIN_LOG4J:
+       case LTTNG_DOMAIN_PYTHON:
+               break;
+       default:
+               ret = LTTNG_ERR_UNKNOWN_DOMAIN;
+               goto error;
+       }
+
        switch (domain->type) {
        case LTTNG_DOMAIN_KERNEL:
        {
@@ -1428,10 +1477,6 @@ int cmd_disable_event(struct ltt_session *session,
        DBG("Disable event command for event \'%s\'", event->name);
 
        event_name = event->name;
-       if (validate_event_name(event_name)) {
-               ret = LTTNG_ERR_INVALID_EVENT_NAME;
-               goto error;
-       }
 
        /* Error out on unhandled search criteria */
        if (event->loglevel_type || event->loglevel != -1 || event->enabled
@@ -1673,7 +1718,7 @@ int cmd_add_context(struct ltt_session *session, enum lttng_domain_type domain,
                                free(attr);
                                goto error;
                        }
-                       free(attr);
+                       channel_attr_destroy(attr);
                        chan_ust_created = 1;
                }
 
@@ -1723,43 +1768,6 @@ end:
        return ret;
 }
 
-static int validate_event_name(const char *name)
-{
-       int ret = 0;
-       const char *c = name;
-       const char *event_name_end = c + LTTNG_SYMBOL_NAME_LEN;
-       bool null_terminated = false;
-
-       /*
-        * Make sure that unescaped wildcards are only used as the last
-        * character of the event name.
-        */
-       while (c < event_name_end) {
-               switch (*c) {
-               case '\0':
-                       null_terminated = true;
-                       goto end;
-               case '\\':
-                       c++;
-                       break;
-               case '*':
-                       if ((c + 1) < event_name_end && *(c + 1)) {
-                               /* Wildcard is not the last character */
-                               ret = LTTNG_ERR_INVALID_EVENT_NAME;
-                               goto end;
-                       }
-               default:
-                       break;
-               }
-               c++;
-       }
-end:
-       if (!ret && !null_terminated) {
-               ret = LTTNG_ERR_INVALID_EVENT_NAME;
-       }
-       return ret;
-}
-
 static inline bool name_starts_with(const char *name, const char *prefix)
 {
        const size_t max_cmp_len = min(strlen(prefix), LTTNG_SYMBOL_NAME_LEN);
@@ -1805,7 +1813,7 @@ static int _cmd_enable_event(struct ltt_session *session,
                struct lttng_event_exclusion *exclusion,
                int wpipe, bool internal_event)
 {
-       int ret, channel_created = 0;
+       int ret = 0, channel_created = 0;
        struct lttng_channel *attr = NULL;
 
        assert(session);
@@ -1815,15 +1823,24 @@ static int _cmd_enable_event(struct ltt_session *session,
        /* If we have a filter, we must have its filter expression */
        assert(!(!!filter_expression ^ !!filter));
 
-       DBG("Enable event command for event \'%s\'", event->name);
+       /* Normalize event name as a globbing pattern */
+       strutils_normalize_star_glob_pattern(event->name);
 
-       rcu_read_lock();
+       /* Normalize exclusion names as globbing patterns */
+       if (exclusion) {
+               size_t i;
 
-       ret = validate_event_name(event->name);
-       if (ret) {
-               goto error;
+               for (i = 0; i < exclusion->count; i++) {
+                       char *name = LTTNG_EVENT_EXCLUSION_NAME_AT(exclusion, i);
+
+                       strutils_normalize_star_glob_pattern(name);
+               }
        }
 
+       DBG("Enable event command for event \'%s\'", event->name);
+
+       rcu_read_lock();
+
        switch (domain->type) {
        case LTTNG_DOMAIN_KERNEL:
        {
@@ -2171,7 +2188,7 @@ error:
        free(filter_expression);
        free(filter);
        free(exclusion);
-       free(attr);
+       channel_attr_destroy(attr);
        rcu_read_unlock();
        return ret;
 }
@@ -2940,8 +2957,8 @@ ssize_t cmd_list_channels(enum lttng_domain_type domain,
 
        if (nb_chan > 0) {
                const size_t channel_size = sizeof(struct lttng_channel) +
-                       sizeof(struct lttcomm_channel_extended);
-               struct lttcomm_channel_extended *channel_exts;
+                       sizeof(struct lttng_channel_extended);
+               struct lttng_channel_extended *channel_exts;
 
                payload_size = nb_chan * channel_size;
                *channels = zmalloc(payload_size);
@@ -2952,7 +2969,12 @@ ssize_t cmd_list_channels(enum lttng_domain_type domain,
 
                channel_exts = ((void *) *channels) +
                                (nb_chan * sizeof(struct lttng_channel));
-               list_lttng_channels(domain, session, *channels, channel_exts);
+               ret = list_lttng_channels(domain, session, *channels, channel_exts);
+               if (ret != LTTNG_OK) {
+                       free(*channels);
+                       *channels = NULL;
+                       goto end;
+               }
        } else {
                *channels = NULL;
        }
@@ -3377,6 +3399,27 @@ end:
        return ret;
 }
 
+static
+int clear_metadata_file(int fd)
+{
+       int ret;
+
+       ret = lseek(fd, 0, SEEK_SET);
+       if (ret < 0) {
+               PERROR("lseek");
+               goto end;
+       }
+
+       ret = ftruncate(fd, 0);
+       if (ret < 0) {
+               PERROR("ftruncate");
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
 static
 int ust_regenerate_metadata(struct ltt_ust_session *usess)
 {
@@ -3398,6 +3441,15 @@ int ust_regenerate_metadata(struct ltt_ust_session *usess)
                memset(registry->metadata, 0, registry->metadata_alloc_len);
                registry->metadata_len = 0;
                registry->metadata_version++;
+               if (registry->metadata_fd > 0) {
+                       /* Clear the metadata file's content. */
+                       ret = clear_metadata_file(registry->metadata_fd);
+                       if (ret) {
+                               pthread_mutex_unlock(&registry->lock);
+                               goto end;
+                       }
+               }
+
                ret = ust_metadata_session_statedump(registry, NULL,
                                registry->major, registry->minor);
                if (ret) {
@@ -3498,7 +3550,6 @@ int cmd_regenerate_statedump(struct ltt_session *session)
                ret = LTTNG_ERR_SESSION_NOT_STARTED;
                goto end;
        }
-       ret = 0;
 
        if (session->kernel_session) {
                ret = kernctl_session_regenerate_statedump(
@@ -3536,6 +3587,94 @@ end:
        return ret;
 }
 
+int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
+               struct notification_thread_handle *notification_thread)
+{
+       int ret;
+       size_t trigger_len;
+       ssize_t sock_recv_len;
+       struct lttng_trigger *trigger = NULL;
+       struct lttng_buffer_view view;
+       struct lttng_dynamic_buffer trigger_buffer;
+
+       lttng_dynamic_buffer_init(&trigger_buffer);
+       trigger_len = (size_t) cmd_ctx->lsm->u.trigger.length;
+       ret = lttng_dynamic_buffer_set_size(&trigger_buffer, trigger_len);
+       if (ret) {
+               ret = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       sock_recv_len = lttcomm_recv_unix_sock(sock, trigger_buffer.data,
+                       trigger_len);
+       if (sock_recv_len < 0 || sock_recv_len != trigger_len) {
+               ERR("Failed to receive \"register trigger\" command payload");
+               /* TODO: should this be a new error enum ? */
+               ret = LTTNG_ERR_INVALID_TRIGGER;
+               goto end;
+       }
+
+       view = lttng_buffer_view_from_dynamic_buffer(&trigger_buffer, 0, -1);
+       if (lttng_trigger_create_from_buffer(&view, &trigger) !=
+                       trigger_len) {
+               ERR("Invalid trigger payload received in \"register trigger\" command");
+               ret = LTTNG_ERR_INVALID_TRIGGER;
+               goto end;
+       }
+
+       ret = notification_thread_command_register_trigger(notification_thread,
+                       trigger);
+       /* Ownership of trigger was transferred. */
+       trigger = NULL;
+end:
+       lttng_trigger_destroy(trigger);
+       lttng_dynamic_buffer_reset(&trigger_buffer);
+       return ret;
+}
+
+int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock,
+               struct notification_thread_handle *notification_thread)
+{
+       int ret;
+       size_t trigger_len;
+       ssize_t sock_recv_len;
+       struct lttng_trigger *trigger = NULL;
+       struct lttng_buffer_view view;
+       struct lttng_dynamic_buffer trigger_buffer;
+
+       lttng_dynamic_buffer_init(&trigger_buffer);
+       trigger_len = (size_t) cmd_ctx->lsm->u.trigger.length;
+       ret = lttng_dynamic_buffer_set_size(&trigger_buffer, trigger_len);
+       if (ret) {
+               ret = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       sock_recv_len = lttcomm_recv_unix_sock(sock, trigger_buffer.data,
+                       trigger_len);
+       if (sock_recv_len < 0 || sock_recv_len != trigger_len) {
+               ERR("Failed to receive \"unregister trigger\" command payload");
+               /* TODO: should this be a new error enum ? */
+               ret = LTTNG_ERR_INVALID_TRIGGER;
+               goto end;
+       }
+
+       view = lttng_buffer_view_from_dynamic_buffer(&trigger_buffer, 0, -1);
+       if (lttng_trigger_create_from_buffer(&view, &trigger) !=
+                       trigger_len) {
+               ERR("Invalid trigger payload received in \"unregister trigger\" command");
+               ret = LTTNG_ERR_INVALID_TRIGGER;
+               goto end;
+       }
+
+       ret = notification_thread_command_unregister_trigger(notification_thread,
+                       trigger);
+end:
+       lttng_trigger_destroy(trigger);
+       lttng_dynamic_buffer_reset(&trigger_buffer);
+       return ret;
+}
+
 /*
  * Send relayd sockets from snapshot output to consumer. Ignore request if the
  * snapshot output is *not* set with a remote destination.
This page took 0.028612 seconds and 4 git commands to generate.