+ 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
+ * snapshot output is *not* set with a remote destination.
+ *
+ * Return 0 on success or a LTTNG_ERR code.
+ */
+static int set_relayd_for_snapshot(struct consumer_output *consumer,
+ struct snapshot_output *snap_output, struct ltt_session *session)
+{
+ int ret = LTTNG_OK;
+ struct lttng_ht_iter iter;
+ struct consumer_socket *socket;
+
+ assert(consumer);
+ assert(snap_output);
+ assert(session);
+
+ DBG2("Set relayd object from snapshot output");
+
+ /* Ignore if snapshot consumer output is not network. */
+ if (snap_output->consumer->type != CONSUMER_DST_NET) {
+ goto error;
+ }
+
+ /*
+ * For each consumer socket, create and send the relayd object of the
+ * snapshot output.
+ */
+ rcu_read_lock();
+ cds_lfht_for_each_entry(snap_output->consumer->socks->ht, &iter.iter,
+ socket, node.node) {
+ pthread_mutex_lock(socket->lock);
+ ret = send_consumer_relayd_sockets(0, session->id,
+ snap_output->consumer, socket,
+ session->name, session->hostname,
+ session->live_timer);
+ pthread_mutex_unlock(socket->lock);
+ if (ret != LTTNG_OK) {
+ rcu_read_unlock();
+ goto error;
+ }
+ }
+ rcu_read_unlock();
+
+error:
+ return ret;
+}
+
+/*
+ * Record a kernel snapshot.
+ *
+ * Return LTTNG_OK on success or a LTTNG_ERR code.
+ */
+static int record_kernel_snapshot(struct ltt_kernel_session *ksess,
+ struct snapshot_output *output, struct ltt_session *session,
+ int wait, uint64_t nb_packets_per_stream)
+{
+ int ret;
+
+ assert(ksess);
+ assert(output);
+ assert(session);
+
+
+ /*
+ * Copy kernel session sockets so we can communicate with the right
+ * consumer for the snapshot record command.
+ */
+ ret = consumer_copy_sockets(output->consumer, ksess->consumer);
+ if (ret < 0) {
+ ret = LTTNG_ERR_NOMEM;
+ goto error;
+ }
+
+ ret = set_relayd_for_snapshot(ksess->consumer, output, session);
+ if (ret != LTTNG_OK) {
+ goto error_snapshot;
+ }
+
+ ret = kernel_snapshot_record(ksess, output, wait, nb_packets_per_stream);
+ if (ret != LTTNG_OK) {
+ goto error_snapshot;
+ }
+
+ ret = LTTNG_OK;
+ goto end;
+
+error_snapshot:
+ /* Clean up copied sockets so this output can use some other later on. */
+ consumer_destroy_output_sockets(output->consumer);
+error:
+end:
+ return ret;
+}
+
+/*
+ * Record a UST snapshot.
+ *
+ * Return 0 on success or a LTTNG_ERR error code.
+ */
+static int record_ust_snapshot(struct ltt_ust_session *usess,
+ struct snapshot_output *output, struct ltt_session *session,
+ int wait, uint64_t nb_packets_per_stream)
+{
+ int ret;
+
+ assert(usess);
+ assert(output);
+ assert(session);