+ ret = LTTNG_ERR_UND;
+ goto error;
+ }
+
+ return nb_event;
+
+error:
+ /* Return negative value to differentiate return code */
+ return -ret;
+}
+
+/*
+ * Using the session list, filled a lttng_session array to send back to the
+ * client for session listing.
+ *
+ * The session list lock MUST be acquired before calling this function. Use
+ * session_lock_list() and session_unlock_list().
+ */
+void cmd_list_lttng_sessions(struct lttng_session *sessions, uid_t uid,
+ gid_t gid)
+{
+ int ret;
+ unsigned int i = 0;
+ struct ltt_session *session;
+ struct ltt_session_list *list = session_get_list();
+
+ DBG("Getting all available session for UID %d GID %d",
+ uid, gid);
+ /*
+ * Iterate over session list and append data after the control struct in
+ * the buffer.
+ */
+ cds_list_for_each_entry(session, &list->head, list) {
+ /*
+ * Only list the sessions the user can control.
+ */
+ if (!session_access_ok(session, uid, gid)) {
+ continue;
+ }
+
+ struct ltt_kernel_session *ksess = session->kernel_session;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ if (session->consumer->type == CONSUMER_DST_NET ||
+ (ksess && ksess->consumer->type == CONSUMER_DST_NET) ||
+ (usess && usess->consumer->type == CONSUMER_DST_NET)) {
+ ret = build_network_session_path(sessions[i].path,
+ sizeof(sessions[i].path), session);
+ } else {
+ ret = snprintf(sessions[i].path, sizeof(sessions[i].path), "%s",
+ session->consumer->dst.trace_path);
+ }
+ if (ret < 0) {
+ PERROR("snprintf session path");
+ continue;
+ }
+
+ strncpy(sessions[i].name, session->name, NAME_MAX);
+ sessions[i].name[NAME_MAX - 1] = '\0';
+ sessions[i].enabled = session->active;
+ sessions[i].snapshot_mode = session->snapshot_mode;
+ sessions[i].live_timer_interval = session->live_timer;
+ i++;
+ }
+}
+
+/*
+ * Command LTTNG_DATA_PENDING returning 0 if the data is NOT pending meaning
+ * ready for trace analysis (or any kind of reader) or else 1 for pending data.
+ */
+int cmd_data_pending(struct ltt_session *session)
+{
+ int ret;
+ struct ltt_kernel_session *ksess = session->kernel_session;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ assert(session);
+
+ /* Session MUST be stopped to ask for data availability. */
+ if (session->active) {
+ ret = LTTNG_ERR_SESSION_STARTED;
+ goto error;
+ } else {
+ /*
+ * If stopped, just make sure we've started before else the above call
+ * will always send that there is data pending.
+ *
+ * The consumer assumes that when the data pending command is received,
+ * the trace has been started before or else no output data is written
+ * by the streams which is a condition for data pending. So, this is
+ * *VERY* important that we don't ask the consumer before a start
+ * trace.
+ */
+ if (!session->has_been_started) {
+ ret = 0;
+ goto error;
+ }
+ }
+
+ if (ksess && ksess->consumer) {
+ ret = consumer_is_data_pending(ksess->id, ksess->consumer);
+ if (ret == 1) {
+ /* Data is still being extracted for the kernel. */
+ goto error;
+ }
+ }
+
+ if (usess && usess->consumer) {
+ ret = consumer_is_data_pending(usess->id, usess->consumer);
+ if (ret == 1) {
+ /* Data is still being extracted for the kernel. */
+ goto error;
+ }
+ }
+
+ /* Data is ready to be read by a viewer */
+ ret = 0;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_SNAPSHOT_ADD_OUTPUT from the lttng ctl library.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR code.
+ */
+int cmd_snapshot_add_output(struct ltt_session *session,
+ struct lttng_snapshot_output *output, uint32_t *id)
+{
+ int ret;
+ struct snapshot_output *new_output;
+
+ assert(session);
+ assert(output);
+
+ 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.
+ */
+ if (session->output_traces) {
+ ret = LTTNG_ERR_EPERM;
+ goto error;
+ }
+
+ /* Only one output is allowed until we have the "tee" feature. */
+ if (session->snapshot.nb_output == 1) {
+ ret = LTTNG_ERR_SNAPSHOT_OUTPUT_EXIST;
+ goto error;
+ }
+
+ new_output = snapshot_output_alloc();
+ if (!new_output) {
+ ret = LTTNG_ERR_NOMEM;
+ goto error;
+ }
+
+ ret = snapshot_output_init(output->max_size, output->name,
+ output->ctrl_url, output->data_url, session->consumer, new_output,
+ &session->snapshot);
+ if (ret < 0) {
+ if (ret == -ENOMEM) {
+ ret = LTTNG_ERR_NOMEM;
+ } else {
+ ret = LTTNG_ERR_INVALID;
+ }
+ goto free_error;
+ }
+
+ rcu_read_lock();
+ snapshot_add_output(&session->snapshot, new_output);
+ if (id) {
+ *id = new_output->id;
+ }
+ rcu_read_unlock();
+
+ return LTTNG_OK;
+
+free_error:
+ snapshot_output_destroy(new_output);
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_SNAPSHOT_DEL_OUTPUT from lib lttng ctl.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR code.
+ */
+int cmd_snapshot_del_output(struct ltt_session *session,
+ struct lttng_snapshot_output *output)
+{
+ int ret;
+ struct snapshot_output *sout = NULL;
+
+ assert(session);
+ assert(output);
+
+ rcu_read_lock();
+
+ /*
+ * Permission denied to create an output if the session is not
+ * set in no output mode.
+ */
+ if (session->output_traces) {
+ ret = LTTNG_ERR_EPERM;
+ goto error;
+ }
+
+ if (output->id) {
+ DBG("Cmd snapshot del output id %" PRIu32 " for session %s", output->id,
+ session->name);
+ sout = snapshot_find_output_by_id(output->id, &session->snapshot);
+ } else if (*output->name != '\0') {
+ DBG("Cmd snapshot del output name %s for session %s", output->name,
+ session->name);
+ sout = snapshot_find_output_by_name(output->name, &session->snapshot);
+ }
+ if (!sout) {
+ ret = LTTNG_ERR_INVALID;
+ goto error;
+ }
+
+ snapshot_delete_output(&session->snapshot, sout);
+ snapshot_output_destroy(sout);
+ ret = LTTNG_OK;
+
+error:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Command LTTNG_SNAPSHOT_LIST_OUTPUT from lib lttng ctl.
+ *
+ * If no output is available, outputs is untouched and 0 is returned.
+ *
+ * Return the size of the newly allocated outputs or a negative LTTNG_ERR code.
+ */
+ssize_t cmd_snapshot_list_outputs(struct ltt_session *session,
+ struct lttng_snapshot_output **outputs)
+{
+ int ret, idx = 0;
+ struct lttng_snapshot_output *list = NULL;
+ struct lttng_ht_iter iter;
+ struct snapshot_output *output;
+
+ assert(session);
+ assert(outputs);
+
+ DBG("Cmd snapshot list outputs for session %s", session->name);
+
+ /*
+ * Permission denied to create an output if the session is not
+ * set in no output mode.
+ */
+ if (session->output_traces) {
+ ret = -LTTNG_ERR_EPERM;
+ goto error;
+ }
+
+ if (session->snapshot.nb_output == 0) {
+ ret = 0;
+ goto error;
+ }
+
+ list = zmalloc(session->snapshot.nb_output * sizeof(*list));
+ if (!list) {
+ ret = -LTTNG_ERR_NOMEM;