Fix: truncate the metadata file in shm-path
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index 87c6eb36dd2c6264848b021f772dddfe85abd0d5..cc81906b6267ffc104ee357741d0b099af9fbc3c 100644 (file)
@@ -28,6 +28,7 @@
 #include <common/relayd/relayd.h>
 #include <common/utils.h>
 #include <common/compat/string.h>
+#include <common/kernel-ctl/kernel-ctl.h>
 
 #include "channel.h"
 #include "consumer.h"
@@ -39,6 +40,7 @@
 #include "utils.h"
 #include "syscall.h"
 #include "agent.h"
+#include "buffer-registry.h"
 
 #include "cmd.h"
 
@@ -139,13 +141,105 @@ error:
        return ret;
 }
 
+/*
+ * Get run-time attributes if the session has been started (discarded events,
+ * lost packets).
+ */
+static int get_kernel_runtime_stats(struct ltt_session *session,
+               struct ltt_kernel_channel *kchan, uint64_t *discarded_events,
+               uint64_t *lost_packets)
+{
+       int ret;
+
+       if (!session->has_been_started) {
+               ret = 0;
+               *discarded_events = 0;
+               *lost_packets = 0;
+               goto end;
+       }
+
+       ret = consumer_get_discarded_events(session->id, kchan->fd,
+                       session->kernel_session->consumer,
+                       discarded_events);
+       if (ret < 0) {
+               goto end;
+       }
+
+       ret = consumer_get_lost_packets(session->id, kchan->fd,
+                       session->kernel_session->consumer,
+                       lost_packets);
+       if (ret < 0) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Get run-time attributes if the session has been started (discarded events,
+ * lost packets).
+ */
+static int get_ust_runtime_stats(struct ltt_session *session,
+               struct ltt_ust_channel *uchan, uint64_t *discarded_events,
+               uint64_t *lost_packets)
+{
+       int ret;
+       struct ltt_ust_session *usess;
+
+       if (!discarded_events || !lost_packets) {
+               ret = -1;
+               goto end;
+       }
+
+       usess = session->ust_session;
+       assert(discarded_events);
+       assert(lost_packets);
+
+       if (!usess || !session->has_been_started) {
+               *discarded_events = 0;
+               *lost_packets = 0;
+               ret = 0;
+               goto end;
+       }
+
+       if (usess->buffer_type == LTTNG_BUFFER_PER_UID) {
+               ret = ust_app_uid_get_channel_runtime_stats(usess->id,
+                               &usess->buffer_reg_uid_list,
+                               usess->consumer, uchan->id,
+                               uchan->attr.overwrite,
+                               discarded_events,
+                               lost_packets);
+       } else if (usess->buffer_type == LTTNG_BUFFER_PER_PID) {
+               ret = ust_app_pid_get_channel_runtime_stats(usess,
+                               uchan, usess->consumer,
+                               uchan->attr.overwrite,
+                               discarded_events,
+                               lost_packets);
+               if (ret < 0) {
+                       goto end;
+               }
+               *discarded_events += uchan->per_pid_closed_app_discarded;
+               *lost_packets += uchan->per_pid_closed_app_lost;
+       } else {
+               ERR("Unsupported buffer type");
+               assert(0);
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
 /*
  * Fill lttng_channel array of all channels.
  */
 static void list_lttng_channels(enum lttng_domain_type domain,
-               struct ltt_session *session, struct lttng_channel *channels)
+               struct ltt_session *session, struct lttng_channel *channels,
+               struct lttcomm_channel_extended *chan_exts)
 {
-       int i = 0;
+       int i = 0, ret;
        struct ltt_kernel_channel *kchan;
 
        DBG("Listing channels for session %s", session->name);
@@ -156,9 +250,19 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                if (session->kernel_session != NULL) {
                        cds_list_for_each_entry(kchan,
                                        &session->kernel_session->channel_list.head, list) {
+                               uint64_t discarded_events, lost_packets;
+
+                               ret = get_kernel_runtime_stats(session, kchan,
+                                               &discarded_events, &lost_packets);
+                               if (ret < 0) {
+                                       goto end;
+                               }
                                /* Copy lttng_channel struct to array */
                                memcpy(&channels[i], kchan->channel, sizeof(struct lttng_channel));
                                channels[i].enabled = kchan->enabled;
+                               chan_exts[i].discarded_events =
+                                               discarded_events;
+                               chan_exts[i].lost_packets = lost_packets;
                                i++;
                        }
                }
@@ -171,7 +275,12 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                rcu_read_lock();
                cds_lfht_for_each_entry(session->ust_session->domain_global.channels->ht,
                                &iter.iter, uchan, node.node) {
-                       strncpy(channels[i].name, uchan->name, LTTNG_SYMBOL_NAME_LEN);
+                       uint64_t discarded_events = 0, lost_packets = 0;
+
+                       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;
@@ -182,12 +291,30 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                        channels[i].enabled = uchan->enabled;
                        channels[i].attr.tracefile_size = uchan->tracefile_size;
                        channels[i].attr.tracefile_count = uchan->tracefile_count;
+
+                       /*
+                        * Map enum lttng_ust_output to enum lttng_event_output.
+                        */
                        switch (uchan->attr.output) {
                        case LTTNG_UST_MMAP:
-                       default:
                                channels[i].attr.output = LTTNG_EVENT_MMAP;
                                break;
+                       default:
+                               /*
+                                * LTTNG_UST_MMAP is the only supported UST
+                                * output mode.
+                                */
+                               assert(0);
+                               break;
+                       }
+
+                       ret = get_ust_runtime_stats(session, uchan,
+                                       &discarded_events, &lost_packets);
+                       if (ret < 0) {
+                               break;
                        }
+                       chan_exts[i].discarded_events = discarded_events;
+                       chan_exts[i].lost_packets = lost_packets;
                        i++;
                }
                rcu_read_unlock();
@@ -196,6 +323,9 @@ static void list_lttng_channels(enum lttng_domain_type domain,
        default:
                break;
        }
+
+end:
+       return;
 }
 
 static void increment_extended_len(const char *filter_expression,
@@ -473,7 +603,7 @@ static int list_lttng_kernel_events(char *channel_name,
        if (nb_event == 0) {
                *total_size = 0;
                *events = NULL;
-               goto syscall;
+               goto end;
        }
 
        /* Compute required extended infos size */
@@ -489,7 +619,7 @@ static int list_lttng_kernel_events(char *channel_name,
                goto error;
        }
 
-       extended_at = ((uint8_t *) events) +
+       extended_at = ((void *) *events) +
                nb_event * sizeof(struct lttng_event);
 
        /* Kernel channels */
@@ -536,19 +666,7 @@ static int list_lttng_kernel_events(char *channel_name,
                        &extended_at);
        }
 
-syscall:
-       if (syscall_table) {
-               ssize_t new_size;
-
-               new_size = syscall_list_channel(kchan, events, nb_event);
-               if (new_size < 0) {
-                       free(events);
-                       ret = -new_size;
-                       goto error;
-               }
-               nb_event = new_size;
-       }
-
+end:
        return nb_event;
 
 error:
@@ -643,12 +761,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;
@@ -698,7 +819,8 @@ error:
  * Else, it's stays untouched and a lttcomm error code is returned.
  */
 static int create_connect_relayd(struct lttng_uri *uri,
-               struct lttcomm_relayd_sock **relayd_sock)
+               struct lttcomm_relayd_sock **relayd_sock,
+               struct consumer_output *consumer)
 {
        int ret;
        struct lttcomm_relayd_sock *rsock;
@@ -734,6 +856,8 @@ static int create_connect_relayd(struct lttng_uri *uri,
                        ret = LTTNG_ERR_RELAYD_VERSION_FAIL;
                        goto close_sock;
                }
+               consumer->relay_major_version = rsock->major;
+               consumer->relay_minor_version = rsock->minor;
        } else if (uri->stype == LTTNG_STREAM_DATA) {
                DBG3("Creating relayd data socket from URI");
        } else {
@@ -769,7 +893,7 @@ static int send_consumer_relayd_socket(enum lttng_domain_type domain,
        struct lttcomm_relayd_sock *rsock = NULL;
 
        /* Connect to relayd and make version check if uri is the control. */
-       ret = create_connect_relayd(relayd_uri, &rsock);
+       ret = create_connect_relayd(relayd_uri, &rsock, consumer);
        if (ret != LTTNG_OK) {
                goto error;
        }
@@ -904,6 +1028,10 @@ int cmd_setup_relayd(struct ltt_session *session)
                        /* Session is now ready for network streaming. */
                        session->net_handle = 1;
                }
+               session->consumer->relay_major_version =
+                       usess->consumer->relay_major_version;
+               session->consumer->relay_minor_version =
+                       usess->consumer->relay_minor_version;
        }
 
        if (ksess && ksess->consumer && ksess->consumer->type == CONSUMER_DST_NET
@@ -922,6 +1050,10 @@ int cmd_setup_relayd(struct ltt_session *session)
                        /* Session is now ready for network streaming. */
                        session->net_handle = 1;
                }
+               session->consumer->relay_major_version =
+                       ksess->consumer->relay_major_version;
+               session->consumer->relay_minor_version =
+                       ksess->consumer->relay_minor_version;
        }
 
 error:
@@ -1201,16 +1333,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:
        {
@@ -1684,7 +1806,7 @@ static int _cmd_enable_event(struct ltt_session *session,
                int wpipe, bool internal_event)
 {
        int ret, channel_created = 0;
-       struct lttng_channel *attr;
+       struct lttng_channel *attr = NULL;
 
        assert(session);
        assert(event);
@@ -1727,15 +1849,16 @@ static int _cmd_enable_event(struct ltt_session *session,
                                ret = LTTNG_ERR_FATAL;
                                goto error;
                        }
-                       strncpy(attr->name, channel_name, sizeof(attr->name));
+                       if (lttng_strncpy(attr->name, channel_name,
+                                       sizeof(attr->name))) {
+                               ret = LTTNG_ERR_INVALID;
+                               goto error;
+                       }
 
                        ret = cmd_enable_channel(session, domain, attr, wpipe);
                        if (ret != LTTNG_OK) {
-                               free(attr);
                                goto error;
                        }
-                       free(attr);
-
                        channel_created = 1;
                }
 
@@ -1864,14 +1987,16 @@ static int _cmd_enable_event(struct ltt_session *session,
                                ret = LTTNG_ERR_FATAL;
                                goto error;
                        }
-                       strncpy(attr->name, channel_name, sizeof(attr->name));
+                       if (lttng_strncpy(attr->name, channel_name,
+                                       sizeof(attr->name))) {
+                               ret = LTTNG_ERR_INVALID;
+                               goto error;
+                       }
 
                        ret = cmd_enable_channel(session, domain, attr, wpipe);
                        if (ret != LTTNG_OK) {
-                               free(attr);
                                goto error;
                        }
-                       free(attr);
 
                        /* Get the newly created channel reference back */
                        uchan = trace_ust_find_channel_by_name(
@@ -2046,6 +2171,7 @@ error:
        free(filter_expression);
        free(filter);
        free(exclusion);
+       free(attr);
        rcu_read_unlock();
        return ret;
 }
@@ -2311,7 +2437,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) {
@@ -2319,7 +2453,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) {
@@ -2327,14 +2461,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;
        }
 
@@ -2622,64 +2748,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.
  */
@@ -3081,11 +3149,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;
        }
 
@@ -3149,7 +3216,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;
        }
 
@@ -3201,19 +3268,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. */
@@ -3223,10 +3290,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,
@@ -3251,11 +3326,246 @@ ssize_t cmd_snapshot_list_outputs(struct ltt_session *session,
        list = NULL;
        ret = session->snapshot.nb_output;
 error:
+       rcu_read_unlock();
        free(list);
+end:
+       return ret;
+}
+
+/*
+ * Check if we can regenerate the metadata for this session.
+ * Only kernel, UST per-uid and non-live sessions are supported.
+ *
+ * Return 0 if the metadata can be generated, a LTTNG_ERR code otherwise.
+ */
+static
+int check_regenerate_metadata_support(struct ltt_session *session)
+{
+       int ret;
+
+       assert(session);
+
+       if (session->live_timer != 0) {
+               ret = LTTNG_ERR_LIVE_SESSION;
+               goto end;
+       }
+       if (!session->active) {
+               ret = LTTNG_ERR_SESSION_NOT_STARTED;
+               goto end;
+       }
+       if (session->ust_session) {
+               switch (session->ust_session->buffer_type) {
+               case LTTNG_BUFFER_PER_UID:
+                       break;
+               case LTTNG_BUFFER_PER_PID:
+                       ret = LTTNG_ERR_PER_PID_SESSION;
+                       goto end;
+               default:
+                       assert(0);
+                       ret = LTTNG_ERR_UNK;
+                       goto end;
+               }
+       }
+       if (session->consumer->type == CONSUMER_DST_NET &&
+                       session->consumer->relay_minor_version < 8) {
+               ret = LTTNG_ERR_RELAYD_VERSION_FAIL;
+               goto end;
+       }
+       ret = 0;
+
+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)
+{
+       int ret = 0;
+       struct buffer_reg_uid *uid_reg = NULL;
+       struct buffer_reg_session *session_reg = NULL;
+
+       rcu_read_lock();
+       cds_list_for_each_entry(uid_reg, &usess->buffer_reg_uid_list, lnode) {
+               struct ust_registry_session *registry;
+               struct ust_registry_channel *chan;
+               struct lttng_ht_iter iter_chan;
+
+               session_reg = uid_reg->registry;
+               registry = session_reg->reg.ust;
+
+               pthread_mutex_lock(&registry->lock);
+               registry->metadata_len_sent = 0;
+               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) {
+                       pthread_mutex_unlock(&registry->lock);
+                       ERR("Failed to generate session metadata (err = %d)",
+                                       ret);
+                       goto end;
+               }
+               cds_lfht_for_each_entry(registry->channels->ht, &iter_chan.iter,
+                               chan, node.node) {
+                       struct ust_registry_event *event;
+                       struct lttng_ht_iter iter_event;
+
+                       ret = ust_metadata_channel_statedump(registry, chan);
+                       if (ret) {
+                               pthread_mutex_unlock(&registry->lock);
+                               ERR("Failed to generate channel metadata "
+                                               "(err = %d)", ret);
+                               goto end;
+                       }
+                       cds_lfht_for_each_entry(chan->ht->ht, &iter_event.iter,
+                                       event, node.node) {
+                               ret = ust_metadata_event_statedump(registry,
+                                               chan, event);
+                               if (ret) {
+                                       pthread_mutex_unlock(&registry->lock);
+                                       ERR("Failed to generate event metadata "
+                                                       "(err = %d)", ret);
+                                       goto end;
+                               }
+                       }
+               }
+               pthread_mutex_unlock(&registry->lock);
+       }
+
+end:
        rcu_read_unlock();
        return ret;
 }
 
+/*
+ * 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
+ * supported and return an error.
+ *
+ * Return 0 on success or else a LTTNG_ERR code.
+ */
+int cmd_regenerate_metadata(struct ltt_session *session)
+{
+       int ret;
+
+       assert(session);
+
+       ret = check_regenerate_metadata_support(session);
+       if (ret) {
+               goto end;
+       }
+
+       if (session->kernel_session) {
+               ret = kernctl_session_regenerate_metadata(
+                               session->kernel_session->fd);
+               if (ret < 0) {
+                       ERR("Failed to regenerate the kernel metadata");
+                       goto end;
+               }
+       }
+
+       if (session->ust_session) {
+               ret = ust_regenerate_metadata(session->ust_session);
+               if (ret < 0) {
+                       ERR("Failed to regenerate the UST metadata");
+                       goto end;
+               }
+       }
+       DBG("Cmd metadata regenerate for session %s", session->name);
+       ret = LTTNG_OK;
+
+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;
+}
+
 /*
  * Send relayd sockets from snapshot output to consumer. Ignore request if the
  * snapshot output is *not* set with a remote destination.
@@ -3317,13 +3627,6 @@ static int record_kernel_snapshot(struct ltt_kernel_session *ksess,
        assert(output);
        assert(session);
 
-       /* Get the datetime for the snapshot output directory. */
-       ret = utils_get_current_time_str("%Y%m%d-%H%M%S", output->datetime,
-                       sizeof(output->datetime));
-       if (!ret) {
-               ret = LTTNG_ERR_INVALID;
-               goto error;
-       }
 
        /*
         * Copy kernel session sockets so we can communicate with the right
@@ -3371,14 +3674,6 @@ static int record_ust_snapshot(struct ltt_ust_session *usess,
        assert(output);
        assert(session);
 
-       /* Get the datetime for the snapshot output directory. */
-       ret = utils_get_current_time_str("%Y%m%d-%H%M%S", output->datetime,
-                       sizeof(output->datetime));
-       if (!ret) {
-               ret = LTTNG_ERR_INVALID;
-               goto error;
-       }
-
        /*
         * Copy UST session sockets so we can communicate with the right
         * consumer for the snapshot record command.
@@ -3400,9 +3695,6 @@ static int record_ust_snapshot(struct ltt_ust_session *usess,
                case EINVAL:
                        ret = LTTNG_ERR_INVALID;
                        break;
-               case ENODATA:
-                       ret = LTTNG_ERR_SNAPSHOT_NODATA;
-                       break;
                default:
                        ret = LTTNG_ERR_SNAPSHOT_FAIL;
                        break;
@@ -3520,18 +3812,27 @@ int cmd_snapshot_record(struct ltt_session *session,
        unsigned int use_tmp_output = 0;
        struct snapshot_output tmp_output;
        unsigned int snapshot_success = 0;
+       char datetime[16];
 
        assert(session);
        assert(output);
 
        DBG("Cmd snapshot record for session %s", session->name);
 
+       /* Get the datetime for the snapshot output directory. */
+       ret = utils_get_current_time_str("%Y%m%d-%H%M%S", datetime,
+                       sizeof(datetime));
+       if (!ret) {
+               ret = LTTNG_ERR_INVALID;
+               goto error;
+       }
+
        /*
         * Permission denied to 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;
        }
 
@@ -3556,138 +3857,104 @@ int cmd_snapshot_record(struct ltt_session *session,
                }
                /* Use the global session count for the temporary snapshot. */
                tmp_output.nb_snapshot = session->snapshot.nb_snapshot;
+
+               /* Use the global datetime */
+               memcpy(tmp_output.datetime, datetime, sizeof(datetime));
                use_tmp_output = 1;
        }
 
-       if (session->kernel_session) {
-               struct ltt_kernel_session *ksess = session->kernel_session;
+       if (use_tmp_output) {
+               int64_t nb_packets_per_stream;
 
-               if (use_tmp_output) {
-                       int64_t nb_packets_per_stream;
+               nb_packets_per_stream = get_session_nb_packets_per_stream(session,
+                               tmp_output.max_size);
+               if (nb_packets_per_stream < 0) {
+                       ret = LTTNG_ERR_MAX_SIZE_INVALID;
+                       goto error;
+               }
 
-                       nb_packets_per_stream = get_session_nb_packets_per_stream(session,
-                                       tmp_output.max_size);
-                       if (nb_packets_per_stream < 0) {
-                               ret = LTTNG_ERR_MAX_SIZE_INVALID;
+               if (session->kernel_session) {
+                       ret = record_kernel_snapshot(session->kernel_session,
+                                       &tmp_output, session,
+                                       wait, nb_packets_per_stream);
+                       if (ret != LTTNG_OK) {
                                goto error;
                        }
-                       ret = record_kernel_snapshot(ksess, &tmp_output, session,
+               }
+
+               if (session->ust_session) {
+                       ret = record_ust_snapshot(session->ust_session,
+                                       &tmp_output, session,
                                        wait, nb_packets_per_stream);
                        if (ret != LTTNG_OK) {
                                goto error;
                        }
-                       snapshot_success = 1;
-               } else {
-                       struct snapshot_output *sout;
-                       struct lttng_ht_iter iter;
-
-                       rcu_read_lock();
-                       cds_lfht_for_each_entry(session->snapshot.output_ht->ht,
-                                       &iter.iter, sout, node.node) {
-                               int64_t nb_packets_per_stream;
-
-                               /*
-                                * Make a local copy of the output and assign the possible
-                                * temporary value given by the caller.
-                                */
-                               memset(&tmp_output, 0, sizeof(tmp_output));
-                               memcpy(&tmp_output, sout, sizeof(tmp_output));
-
-                               if (output->max_size != (uint64_t) -1ULL) {
-                                       tmp_output.max_size = output->max_size;
-                               }
+               }
 
-                               nb_packets_per_stream = get_session_nb_packets_per_stream(session,
-                                               tmp_output.max_size);
-                               if (nb_packets_per_stream < 0) {
-                                       ret = LTTNG_ERR_MAX_SIZE_INVALID;
-                                       goto error;
-                               }
+               snapshot_success = 1;
+       } else {
+               struct snapshot_output *sout;
+               struct lttng_ht_iter iter;
 
-                               /* Use temporary name. */
-                               if (*output->name != '\0') {
-                                       strncpy(tmp_output.name, output->name,
-                                                       sizeof(tmp_output.name));
-                               }
+               rcu_read_lock();
+               cds_lfht_for_each_entry(session->snapshot.output_ht->ht,
+                               &iter.iter, sout, node.node) {
+                       int64_t nb_packets_per_stream;
 
-                               tmp_output.nb_snapshot = session->snapshot.nb_snapshot;
+                       /*
+                        * Make a local copy of the output and assign the possible
+                        * temporary value given by the caller.
+                        */
+                       memset(&tmp_output, 0, sizeof(tmp_output));
+                       memcpy(&tmp_output, sout, sizeof(tmp_output));
 
-                               ret = record_kernel_snapshot(ksess, &tmp_output,
-                                               session, wait, nb_packets_per_stream);
-                               if (ret != LTTNG_OK) {
-                                       rcu_read_unlock();
-                                       goto error;
-                               }
-                               snapshot_success = 1;
+                       if (output->max_size != (uint64_t) -1ULL) {
+                               tmp_output.max_size = output->max_size;
                        }
-                       rcu_read_unlock();
-               }
-       }
-
-       if (session->ust_session) {
-               struct ltt_ust_session *usess = session->ust_session;
-
-               if (use_tmp_output) {
-                       int64_t nb_packets_per_stream;
 
                        nb_packets_per_stream = get_session_nb_packets_per_stream(session,
                                        tmp_output.max_size);
                        if (nb_packets_per_stream < 0) {
                                ret = LTTNG_ERR_MAX_SIZE_INVALID;
+                               rcu_read_unlock();
                                goto error;
                        }
-                       ret = record_ust_snapshot(usess, &tmp_output, session,
-                                       wait, nb_packets_per_stream);
-                       if (ret != LTTNG_OK) {
-                               goto error;
-                       }
-                       snapshot_success = 1;
-               } else {
-                       struct snapshot_output *sout;
-                       struct lttng_ht_iter iter;
 
-                       rcu_read_lock();
-                       cds_lfht_for_each_entry(session->snapshot.output_ht->ht,
-                                       &iter.iter, sout, node.node) {
-                               int64_t nb_packets_per_stream;
-
-                               /*
-                                * Make a local copy of the output and assign the possible
-                                * temporary value given by the caller.
-                                */
-                               memset(&tmp_output, 0, sizeof(tmp_output));
-                               memcpy(&tmp_output, sout, sizeof(tmp_output));
-
-                               if (output->max_size != (uint64_t) -1ULL) {
-                                       tmp_output.max_size = output->max_size;
-                               }
-
-                               nb_packets_per_stream = get_session_nb_packets_per_stream(session,
-                                               tmp_output.max_size);
-                               if (nb_packets_per_stream < 0) {
-                                       ret = LTTNG_ERR_MAX_SIZE_INVALID;
+                       /* Use temporary name. */
+                       if (*output->name != '\0') {
+                               if (lttng_strncpy(tmp_output.name, output->name,
+                                               sizeof(tmp_output.name))) {
+                                       ret = LTTNG_ERR_INVALID;
                                        rcu_read_unlock();
                                        goto error;
                                }
+                       }
 
-                               /* Use temporary name. */
-                               if (*output->name != '\0') {
-                                       strncpy(tmp_output.name, output->name,
-                                                       sizeof(tmp_output.name));
-                               }
+                       tmp_output.nb_snapshot = session->snapshot.nb_snapshot;
+                       memcpy(tmp_output.datetime, datetime, sizeof(datetime));
 
-                               tmp_output.nb_snapshot = session->snapshot.nb_snapshot;
+                       if (session->kernel_session) {
+                               ret = record_kernel_snapshot(session->kernel_session,
+                                               &tmp_output, session,
+                                               wait, nb_packets_per_stream);
+                               if (ret != LTTNG_OK) {
+                                       rcu_read_unlock();
+                                       goto error;
+                               }
+                       }
 
-                               ret = record_ust_snapshot(usess, &tmp_output, session,
+                       if (session->ust_session) {
+                               ret = record_ust_snapshot(session->ust_session,
+                                               &tmp_output, session,
                                                wait, nb_packets_per_stream);
                                if (ret != LTTNG_OK) {
                                        rcu_read_unlock();
                                        goto error;
                                }
-                               snapshot_success = 1;
                        }
-                       rcu_read_unlock();
+                       snapshot_success = 1;
                }
+               rcu_read_unlock();
        }
 
        if (snapshot_success) {
This page took 0.035116 seconds and 4 git commands to generate.