Fix: do not flag consumer as disabled on relayd comm failure
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index d443d7926b7d9c25fc1b3dcdcbb8b1ced0bc97a4..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++;
                        }
                }
@@ -277,7 +293,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;
@@ -305,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) {
@@ -322,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,
@@ -758,12 +786,15 @@ static int add_uri_to_consumer(struct consumer_output *consumer,
                DBG2("Setting trace directory path from URI to %s", uri->dst.path);
                memset(consumer->dst.trace_path, 0,
                                sizeof(consumer->dst.trace_path));
-               strncpy(consumer->dst.trace_path, uri->dst.path,
-                               sizeof(consumer->dst.trace_path));
+               /* Explicit length checks for strcpy and strcat. */
+               if (strlen(uri->dst.path) + strlen(default_trace_dir)
+                               >= sizeof(consumer->dst.trace_path)) {
+                       ret = LTTNG_ERR_FATAL;
+                       goto error;
+               }
+               strcpy(consumer->dst.trace_path, uri->dst.path);
                /* Append default trace dir */
-               strncat(consumer->dst.trace_path, default_trace_dir,
-                               sizeof(consumer->dst.trace_path) -
-                               strlen(consumer->dst.trace_path) - 1);
+               strcat(consumer->dst.trace_path, default_trace_dir);
                /* Flag consumer as local. */
                consumer->type = CONSUMER_DST_LOCAL;
                break;
@@ -889,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);
 
@@ -929,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
@@ -941,6 +968,10 @@ error:
                 */
                consumer->enabled = 0;
        }
+       (void) relayd_close(rsock);
+       free(rsock);
+
+relayd_comm_error:
        return ret;
 }
 
@@ -1327,13 +1358,27 @@ 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;
+       /* 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;
        }
 
@@ -1432,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
@@ -1677,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;
                }
 
@@ -1727,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);
@@ -1809,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);
@@ -1819,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:
        {
@@ -2175,7 +2188,7 @@ error:
        free(filter_expression);
        free(filter);
        free(exclusion);
-       free(attr);
+       channel_attr_destroy(attr);
        rcu_read_unlock();
        return ret;
 }
@@ -2441,7 +2454,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) {
@@ -2449,7 +2470,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) {
@@ -2457,14 +2478,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;
        }
 
@@ -2752,64 +2765,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.
  */
@@ -3002,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);
@@ -3014,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;
        }
@@ -3211,11 +3171,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;
        }
 
@@ -3279,7 +3238,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;
        }
 
@@ -3331,19 +3290,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. */
@@ -3353,10 +3312,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,
@@ -3381,8 +3348,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;
 }
 
@@ -3393,7 +3361,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;
 
@@ -3432,7 +3400,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;
@@ -3452,6 +3441,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) {
@@ -3493,7 +3491,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
@@ -3501,19 +3499,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");
@@ -3522,7 +3520,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;
@@ -3535,6 +3533,147 @@ 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;
+       }
+
+       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);
+       /* 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
@@ -3802,7 +3941,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;
        }
 
@@ -3892,8 +4031,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.032692 seconds and 4 git commands to generate.