+ 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) {
+ cmd_ret = LTTNG_ERR_MAX_SIZE_INVALID;
+ goto error;
+ }
+
+ if (session->kernel_session) {
+ cmd_ret = record_kernel_snapshot(session->kernel_session,
+ &tmp_output, session,
+ wait, nb_packets_per_stream);
+ if (cmd_ret != LTTNG_OK) {
+ goto error;
+ }
+ }
+
+ if (session->ust_session) {
+ cmd_ret = record_ust_snapshot(session->ust_session,
+ &tmp_output, session,
+ wait, nb_packets_per_stream);
+ if (cmd_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) {
+ cmd_ret = LTTNG_ERR_MAX_SIZE_INVALID;
+ rcu_read_unlock();
+ goto error;
+ }
+
+ /* Use temporary name. */
+ if (*output->name != '\0') {
+ if (lttng_strncpy(tmp_output.name, output->name,
+ sizeof(tmp_output.name))) {
+ cmd_ret = LTTNG_ERR_INVALID;
+ rcu_read_unlock();
+ goto error;
+ }
+ }
+
+ tmp_output.nb_snapshot = session->snapshot.nb_snapshot;
+ memcpy(tmp_output.datetime, datetime, sizeof(datetime));
+
+ if (session->kernel_session) {
+ cmd_ret = record_kernel_snapshot(session->kernel_session,
+ &tmp_output, session,
+ wait, nb_packets_per_stream);
+ if (cmd_ret != LTTNG_OK) {
+ rcu_read_unlock();
+ goto error;
+ }
+ }
+
+ if (session->ust_session) {
+ cmd_ret = record_ust_snapshot(session->ust_session,
+ &tmp_output, session,
+ wait, nb_packets_per_stream);
+ if (cmd_ret != LTTNG_OK) {
+ rcu_read_unlock();
+ goto error;
+ }
+ }
+ snapshot_success = 1;
+ }
+ rcu_read_unlock();
+ }
+
+ if (snapshot_success) {
+ session->snapshot.nb_snapshot++;
+ } else {
+ cmd_ret = LTTNG_ERR_SNAPSHOT_FAIL;
+ }
+
+error:
+ return cmd_ret;
+}
+
+/*
+ * Command LTTNG_SET_SESSION_SHM_PATH processed by the client thread.
+ */
+int cmd_set_session_shm_path(struct ltt_session *session,
+ const char *shm_path)
+{
+ /* Safety net */
+ assert(session);
+
+ /*
+ * Can only set shm path before session is started.
+ */
+ if (session->has_been_started) {
+ return LTTNG_ERR_SESSION_STARTED;
+ }
+
+ strncpy(session->shm_path, shm_path,
+ sizeof(session->shm_path));
+ session->shm_path[sizeof(session->shm_path) - 1] = '\0';
+
+ return 0;
+}
+
+/*
+ * Command LTTNG_ROTATE_SESSION from the lttng-ctl library.
+ *
+ * Ask the consumer to rotate the session output directory.
+ * The session lock must be held.
+ *
+ * Returns LTTNG_OK on success or else a negative LTTng error code.
+ */
+int cmd_rotate_session(struct ltt_session *session,
+ struct lttng_rotate_session_return *rotate_return)
+{
+ int ret;
+ enum lttng_error_code cmd_ret = LTTNG_OK;
+ size_t strf_ret;
+ struct tm *timeinfo;
+ char datetime[21];
+ time_t now;
+ /*
+ * Used to roll-back timestamps in case of failure to launch the
+ * rotation.
+ */
+ time_t original_last_chunk_start_ts, original_current_chunk_start_ts;
+
+ assert(session);
+
+ if (!session->has_been_started) {
+ cmd_ret = LTTNG_ERR_START_SESSION_ONCE;
+ goto end;
+ }
+
+ if (session->live_timer || !session->output_traces) {
+ cmd_ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE;
+ goto end;
+ }
+
+ /*
+ * Unsupported feature in lttng-relayd before 2.11.
+ */
+ if (session->consumer->type == CONSUMER_DST_NET &&
+ (session->consumer->relay_major_version == 2 &&
+ session->consumer->relay_minor_version < 11)) {
+ cmd_ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE_RELAY;
+ goto end;
+ }
+
+ if (session->rotation_state == LTTNG_ROTATION_STATE_ONGOING) {
+ DBG("Refusing to launch a rotation; a rotation is already in progress for session %s",
+ session->name);
+ cmd_ret = LTTNG_ERR_ROTATION_PENDING;
+ goto end;
+ }
+