Add support for "full" star globbing patterns in event names and filters
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index 1327e42e4ddfa8efdd5a550179000a8f77f34150..f3ff25642e701a0f83e78bbfd02144c1a118dfdb 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-internal.h>
+#include <common/string-utils/string-utils.h>
 
 #include "channel.h"
 #include "consumer.h"
@@ -41,6 +48,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 +62,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,
@@ -237,7 +245,7 @@ end:
  */
 static void 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;
        struct ltt_kernel_channel *kchan;
@@ -251,6 +259,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 +275,8 @@ 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;
                                i++;
                        }
                }
@@ -277,7 +291,10 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                                &iter.iter, uchan, node.node) {
                        uint64_t discarded_events = 0, lost_packets = 0;
 
-                       strncpy(channels[i].name, uchan->name, LTTNG_SYMBOL_NAME_LEN);
+                       if (lttng_strncpy(channels[i].name, uchan->name,
+                                       LTTNG_SYMBOL_NAME_LEN)) {
+                               break;
+                       }
                        channels[i].attr.overwrite = uchan->attr.overwrite;
                        channels[i].attr.subbuf_size = uchan->attr.subbuf_size;
                        channels[i].attr.num_subbuf = uchan->attr.num_subbuf;
@@ -312,6 +329,8 @@ 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 =
+                                       uchan->monitor_timer_interval;
                        i++;
                }
                rcu_read_unlock();
@@ -1330,16 +1349,6 @@ int cmd_enable_channel(struct ltt_session *session,
                attr->attr.switch_timer_interval = 0;
        }
 
-       /*
-        * The ringbuffer (both in user space and kernel) behave badly in overwrite
-        * mode and with less than 2 subbuf so block it right away and send back an
-        * invalid attribute error.
-        */
-       if (attr->attr.overwrite && attr->attr.num_subbuf < 2) {
-               ret = LTTNG_ERR_INVALID;
-               goto error;
-       }
-
        switch (domain->type) {
        case LTTNG_DOMAIN_KERNEL:
        {
@@ -1435,10 +1444,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
@@ -1680,7 +1685,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;
                }
 
@@ -1730,43 +1735,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);
@@ -1812,7 +1780,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);
@@ -1822,15 +1790,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:
        {
@@ -2178,7 +2155,7 @@ error:
        free(filter_expression);
        free(filter);
        free(exclusion);
-       free(attr);
+       channel_attr_destroy(attr);
        rcu_read_unlock();
        return ret;
 }
@@ -2444,7 +2421,15 @@ int cmd_stop_trace(struct ltt_session *session)
        if (ksession && ksession->active) {
                DBG("Stop kernel tracing");
 
-               /* Flush metadata if exist */
+               ret = kernel_stop_session(ksession);
+               if (ret < 0) {
+                       ret = LTTNG_ERR_KERN_STOP_FAIL;
+                       goto error;
+               }
+
+               kernel_wait_quiescent(kernel_tracer_fd);
+
+               /* Flush metadata after stopping (if exists) */
                if (ksession->metadata_stream_fd >= 0) {
                        ret = kernel_metadata_flush_buffer(ksession->metadata_stream_fd);
                        if (ret < 0) {
@@ -2452,7 +2437,7 @@ int cmd_stop_trace(struct ltt_session *session)
                        }
                }
 
-               /* Flush all buffers before stopping */
+               /* Flush all buffers after stopping */
                cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) {
                        ret = kernel_flush_buffer(kchan);
                        if (ret < 0) {
@@ -2460,14 +2445,6 @@ int cmd_stop_trace(struct ltt_session *session)
                        }
                }
 
-               ret = kernel_stop_session(ksession);
-               if (ret < 0) {
-                       ret = LTTNG_ERR_KERN_STOP_FAIL;
-                       goto error;
-               }
-
-               kernel_wait_quiescent(kernel_tracer_fd);
-
                ksession->active = 0;
        }
 
@@ -2755,64 +2732,6 @@ int cmd_destroy_session(struct ltt_session *session, int wpipe)
        return ret;
 }
 
-/*
- * Command LTTNG_CALIBRATE processed by the client thread.
- */
-int cmd_calibrate(enum lttng_domain_type domain,
-               struct lttng_calibrate *calibrate)
-{
-       int ret;
-
-       switch (domain) {
-       case LTTNG_DOMAIN_KERNEL:
-       {
-               struct lttng_kernel_calibrate kcalibrate;
-
-               switch (calibrate->type) {
-               case LTTNG_CALIBRATE_FUNCTION:
-               default:
-                       /* Default and only possible calibrate option. */
-                       kcalibrate.type = LTTNG_KERNEL_CALIBRATE_KRETPROBE;
-                       break;
-               }
-
-               ret = kernel_calibrate(kernel_tracer_fd, &kcalibrate);
-               if (ret < 0) {
-                       ret = LTTNG_ERR_KERN_ENABLE_FAIL;
-                       goto error;
-               }
-               break;
-       }
-       case LTTNG_DOMAIN_UST:
-       {
-               struct lttng_ust_calibrate ucalibrate;
-
-               switch (calibrate->type) {
-               case LTTNG_CALIBRATE_FUNCTION:
-               default:
-                       /* Default and only possible calibrate option. */
-                       ucalibrate.type = LTTNG_UST_CALIBRATE_TRACEPOINT;
-                       break;
-               }
-
-               ret = ust_app_calibrate_glb(&ucalibrate);
-               if (ret < 0) {
-                       ret = LTTNG_ERR_UST_CALIBRATE_FAIL;
-                       goto error;
-               }
-               break;
-       }
-       default:
-               ret = LTTNG_ERR_UND;
-               goto error;
-       }
-
-       ret = LTTNG_OK;
-
-error:
-       return ret;
-}
-
 /*
  * Command LTTNG_REGISTER_CONSUMER processed by the client thread.
  */
@@ -3005,8 +2924,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);
@@ -3214,11 +3133,10 @@ int cmd_snapshot_add_output(struct ltt_session *session,
        DBG("Cmd snapshot add output for session %s", session->name);
 
        /*
-        * Permission denied to create an output if the session is not
-        * set in no output mode.
+        * Can't create an output if the session is not set in no-output mode.
         */
        if (session->output_traces) {
-               ret = LTTNG_ERR_EPERM;
+               ret = LTTNG_ERR_NOT_SNAPSHOT_SESSION;
                goto error;
        }
 
@@ -3282,7 +3200,7 @@ int cmd_snapshot_del_output(struct ltt_session *session,
         * set in no output mode.
         */
        if (session->output_traces) {
-               ret = LTTNG_ERR_EPERM;
+               ret = LTTNG_ERR_NOT_SNAPSHOT_SESSION;
                goto error;
        }
 
@@ -3334,19 +3252,19 @@ ssize_t cmd_snapshot_list_outputs(struct ltt_session *session,
         * set in no output mode.
         */
        if (session->output_traces) {
-               ret = -LTTNG_ERR_EPERM;
-               goto error;
+               ret = -LTTNG_ERR_NOT_SNAPSHOT_SESSION;
+               goto end;
        }
 
        if (session->snapshot.nb_output == 0) {
                ret = 0;
-               goto error;
+               goto end;
        }
 
        list = zmalloc(session->snapshot.nb_output * sizeof(*list));
        if (!list) {
                ret = -LTTNG_ERR_NOMEM;
-               goto error;
+               goto end;
        }
 
        /* Copy list from session to the new list object. */
@@ -3356,10 +3274,18 @@ ssize_t cmd_snapshot_list_outputs(struct ltt_session *session,
                assert(output->consumer);
                list[idx].id = output->id;
                list[idx].max_size = output->max_size;
-               strncpy(list[idx].name, output->name, sizeof(list[idx].name));
+               if (lttng_strncpy(list[idx].name, output->name,
+                               sizeof(list[idx].name))) {
+                       ret = -LTTNG_ERR_INVALID;
+                       goto error;
+               }
                if (output->consumer->type == CONSUMER_DST_LOCAL) {
-                       strncpy(list[idx].ctrl_url, output->consumer->dst.trace_path,
-                                       sizeof(list[idx].ctrl_url));
+                       if (lttng_strncpy(list[idx].ctrl_url,
+                                       output->consumer->dst.trace_path,
+                                       sizeof(list[idx].ctrl_url))) {
+                               ret = -LTTNG_ERR_INVALID;
+                               goto error;
+                       }
                } else {
                        /* Control URI. */
                        ret = uri_to_str_url(&output->consumer->dst.net.control,
@@ -3384,8 +3310,9 @@ ssize_t cmd_snapshot_list_outputs(struct ltt_session *session,
        list = NULL;
        ret = session->snapshot.nb_output;
 error:
-       free(list);
        rcu_read_unlock();
+       free(list);
+end:
        return ret;
 }
 
@@ -3396,7 +3323,7 @@ error:
  * Return 0 if the metadata can be generated, a LTTNG_ERR code otherwise.
  */
 static
-int check_metadata_regenerate_support(struct ltt_session *session)
+int check_regenerate_metadata_support(struct ltt_session *session)
 {
        int ret;
 
@@ -3435,7 +3362,28 @@ end:
 }
 
 static
-int ust_metadata_regenerate(struct ltt_ust_session *usess)
+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)
 {
        int ret = 0;
        struct buffer_reg_uid *uid_reg = NULL;
@@ -3455,6 +3403,15 @@ int ust_metadata_regenerate(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) {
@@ -3496,7 +3453,7 @@ end:
 }
 
 /*
- * Command LTTNG_METADATA_REGENERATE from the lttng-ctl library.
+ * Command LTTNG_REGENERATE_METADATA from the lttng-ctl library.
  *
  * Ask the consumer to truncate the existing metadata file(s) and
  * then regenerate the metadata. Live and per-pid sessions are not
@@ -3504,19 +3461,19 @@ end:
  *
  * Return 0 on success or else a LTTNG_ERR code.
  */
-int cmd_metadata_regenerate(struct ltt_session *session)
+int cmd_regenerate_metadata(struct ltt_session *session)
 {
        int ret;
 
        assert(session);
 
-       ret = check_metadata_regenerate_support(session);
+       ret = check_regenerate_metadata_support(session);
        if (ret) {
                goto end;
        }
 
        if (session->kernel_session) {
-               ret = kernctl_session_metadata_regenerate(
+               ret = kernctl_session_regenerate_metadata(
                                session->kernel_session->fd);
                if (ret < 0) {
                        ERR("Failed to regenerate the kernel metadata");
@@ -3525,7 +3482,7 @@ int cmd_metadata_regenerate(struct ltt_session *session)
        }
 
        if (session->ust_session) {
-               ret = ust_metadata_regenerate(session->ust_session);
+               ret = ust_regenerate_metadata(session->ust_session);
                if (ret < 0) {
                        ERR("Failed to regenerate the UST metadata");
                        goto end;
@@ -3538,6 +3495,144 @@ end:
        return ret;
 }
 
+/*
+ * Command LTTNG_REGENERATE_STATEDUMP from the lttng-ctl library.
+ *
+ * Ask the tracer to regenerate a new statedump.
+ *
+ * Return 0 on success or else a LTTNG_ERR code.
+ */
+int cmd_regenerate_statedump(struct ltt_session *session)
+{
+       int ret;
+
+       assert(session);
+
+       if (!session->active) {
+               ret = LTTNG_ERR_SESSION_NOT_STARTED;
+               goto end;
+       }
+       ret = 0;
+
+       if (session->kernel_session) {
+               ret = kernctl_session_regenerate_statedump(
+                               session->kernel_session->fd);
+               /*
+                * Currently, the statedump in kernel can only fail if out
+                * of memory.
+                */
+               if (ret < 0) {
+                       if (ret == -ENOMEM) {
+                               ret = LTTNG_ERR_REGEN_STATEDUMP_NOMEM;
+                       } else {
+                               ret = LTTNG_ERR_REGEN_STATEDUMP_FAIL;
+                       }
+                       ERR("Failed to regenerate the kernel statedump");
+                       goto end;
+               }
+       }
+
+       if (session->ust_session) {
+               ret = ust_app_regenerate_statedump_all(session->ust_session);
+               /*
+                * Currently, the statedump in UST always returns 0.
+                */
+               if (ret < 0) {
+                       ret = LTTNG_ERR_REGEN_STATEDUMP_FAIL;
+                       ERR("Failed to regenerate the UST statedump");
+                       goto end;
+               }
+       }
+       DBG("Cmd regenerate statedump for session %s", session->name);
+       ret = LTTNG_OK;
+
+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);
+end:
+       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_dynamic_buffer_reset(&trigger_buffer);
+       return ret;
+}
 
 /*
  * Send relayd sockets from snapshot output to consumer. Ignore request if the
@@ -3805,7 +3900,7 @@ int cmd_snapshot_record(struct ltt_session *session,
         * set in no output mode.
         */
        if (session->output_traces) {
-               ret = LTTNG_ERR_EPERM;
+               ret = LTTNG_ERR_NOT_SNAPSHOT_SESSION;
                goto error;
        }
 
@@ -3895,8 +3990,12 @@ int cmd_snapshot_record(struct ltt_session *session,
 
                        /* Use temporary name. */
                        if (*output->name != '\0') {
-                               strncpy(tmp_output.name, output->name,
-                                               sizeof(tmp_output.name));
+                               if (lttng_strncpy(tmp_output.name, output->name,
+                                               sizeof(tmp_output.name))) {
+                                       ret = LTTNG_ERR_INVALID;
+                                       rcu_read_unlock();
+                                       goto error;
+                               }
                        }
 
                        tmp_output.nb_snapshot = session->snapshot.nb_snapshot;
This page took 0.032611 seconds and 5 git commands to generate.