+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ case LTTNG_DOMAIN_UST_PID:
+ break;
+ default:
+ ret = LTTCOMM_UNKNOWN_DOMAIN;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Copy channel from attributes and set it in the application channel list.
+ */
+/*
+static int copy_ust_channel_to_app(struct ltt_ust_session *usess,
+ struct lttng_channel *attr, struct ust_app *app)
+{
+ int ret;
+ struct ltt_ust_channel *uchan, *new_chan;
+
+ uchan = trace_ust_get_channel_by_key(usess->channels, attr->name);
+ if (uchan == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ new_chan = trace_ust_create_channel(attr, usess->path);
+ if (new_chan == NULL) {
+ PERROR("malloc ltt_ust_channel");
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ ret = channel_ust_copy(new_chan, uchan);
+ if (ret < 0) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+*/
+
+/*
+ * Command LTTNG_ENABLE_CHANNEL processed by the client thread.
+ */
+static int cmd_enable_channel(struct ltt_session *session,
+ struct lttng_domain *domain, struct lttng_channel *attr)
+{
+ int ret;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ DBG("Enabling channel %s for session %s", session->name, attr->name);
+
+ switch (domain->type) {
+ case LTTNG_DOMAIN_KERNEL:
+ {
+ struct ltt_kernel_channel *kchan;
+
+ kchan = trace_kernel_get_channel_by_name(attr->name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ ret = channel_kernel_create(session->kernel_session,
+ attr, kernel_poll_pipe[1]);
+ } else {
+ ret = channel_kernel_enable(session->kernel_session, kchan);
+ }
+
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ }
+ case LTTNG_DOMAIN_UST:
+ {
+ struct ltt_ust_channel *uchan;
+
+ DBG2("Enabling channel for LTTNG_DOMAIN_UST domain");
+
+ uchan = trace_ust_find_channel_by_name(usess->domain_global.channels,
+ attr->name);
+ if (uchan == NULL) {
+ uchan = trace_ust_create_channel(attr, usess->path);
+ if (uchan == NULL) {
+ ret = LTTCOMM_UST_CHAN_FAIL;
+ goto error;
+ }
+ rcu_read_lock();
+ hashtable_add_unique(usess->domain_global.channels, &uchan->node);
+ rcu_read_unlock();
+ } else {
+ ret = LTTCOMM_UST_CHAN_EXIST;
+ goto error;
+ }
+
+ /* TODO: Iterate over trace apps to enable that channel */
+
+ break;
+ }
+ case LTTNG_DOMAIN_UST_PID:
+ {
+ /*
+ int sock;
+ struct ltt_ust_channel *uchan;
+ struct ltt_ust_session *usess;
+ struct ust_app *app;
+
+ usess = trace_ust_get_session_by_pid(&session->ust_session_list,
+ domain->attr.pid);
+ if (usess == NULL) {
+ ret = LTTCOMM_UST_CHAN_NOT_FOUND;
+ goto error;
+ }
+
+ app = ust_app_get_by_pid(domain->attr.pid);
+ if (app == NULL) {
+ ret = LTTCOMM_APP_NOT_FOUND;
+ goto error;
+ }
+ sock = app->sock;
+
+ uchan = trace_ust_get_channel_by_name(attr->name, usess);
+ if (uchan == NULL) {
+ ret = channel_ust_create(usess, attr, sock);
+ } else {
+ ret = channel_ust_enable(usess, uchan, sock);
+ }
+
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ ret = copy_ust_channel_to_app(usess, attr, app);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ DBG("UST channel %s created for app sock %d with pid %d",
+ attr->name, app->sock, domain->attr.pid);
+ */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+ default:
+ ret = LTTCOMM_UNKNOWN_DOMAIN;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_DISABLE_EVENT processed by the client thread.
+ */
+static int cmd_disable_event(struct ltt_session *session, int domain,
+ char *channel_name, char *event_name)
+{
+ int ret;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ {
+ struct ltt_kernel_channel *kchan;
+
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ ret = LTTCOMM_KERN_CHAN_NOT_FOUND;
+ goto error;
+ }
+
+ ret = event_kernel_disable_tracepoint(session->kernel_session, kchan, event_name);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ }
+ case LTTNG_DOMAIN_UST:
+ {
+ struct ltt_ust_session *ustsession;
+
+ cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) {
+ struct ltt_ust_channel *ustchan;
+
+ ustchan = trace_ust_get_channel_by_name(channel_name,
+ ustsession);
+ if (ustchan == NULL) {
+ ret = LTTCOMM_KERN_CHAN_NOT_FOUND;
+ goto error;
+ }
+ ret = event_ust_disable_tracepoint(ustsession, ustchan, event_name);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ ustctl_wait_quiescent(ustsession->sock);
+ }
+ break;
+ }
+ case LTTNG_DOMAIN_UST_EXEC_NAME:
+ case LTTNG_DOMAIN_UST_PID:
+ case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
+ default:
+ /* TODO: Other UST domains */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_DISABLE_ALL_EVENT processed by the client thread.
+ */
+static int cmd_disable_event_all(struct ltt_session *session, int domain,
+ char *channel_name)
+{
+ int ret;
+ struct ltt_kernel_channel *kchan;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ ret = LTTCOMM_KERN_CHAN_NOT_FOUND;
+ goto error;
+ }
+
+ ret = event_kernel_disable_all(session->kernel_session, kchan);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_ADD_CONTEXT processed by the client thread.
+ */
+static int cmd_add_context(struct ltt_session *session, int domain,
+ char *channel_name, char *event_name, struct lttng_event_context *ctx)
+{
+ int ret;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ /* Add kernel context to kernel tracer */
+ ret = context_kernel_add(session->kernel_session, ctx,
+ event_name, channel_name);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+ break;
+ case LTTNG_DOMAIN_UST:
+ {
+ struct ltt_ust_session *ustsession;
+
+ cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) {
+ /* Add UST context to UST tracer */
+ ret = context_ust_add(ustsession, ctx,
+ event_name, channel_name);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+ }
+ break;
+ }
+ default:
+ /* TODO: UST other domains */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_ENABLE_EVENT processed by the client thread.
+ */
+static int cmd_enable_event(struct ltt_session *session, int domain,
+ char *channel_name, struct lttng_event *event)
+{
+ int ret;
+ struct lttng_channel *attr;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ {
+ struct ltt_kernel_channel *kchan;
+
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ attr = channel_new_default_attr(domain);
+ if (attr == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+ snprintf(attr->name, NAME_MAX, "%s", channel_name);
+
+ /* This call will notify the kernel thread */
+ ret = channel_kernel_create(session->kernel_session,
+ attr, kernel_poll_pipe[1]);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+ }
+
+ /* Get the newly created kernel channel pointer */
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ /* This sould not happen... */
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ ret = event_kernel_enable_tracepoint(session->kernel_session, kchan, event);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ }
+ case LTTNG_DOMAIN_UST:
+ {
+ struct ltt_ust_session *ustsession;
+
+ cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) {
+ struct ltt_ust_channel *ustchan;
+
+ ustchan = trace_ust_get_channel_by_name(channel_name,
+ ustsession);
+ if (ustchan == NULL) {
+ attr = channel_new_default_attr(domain);
+ if (attr == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+ snprintf(attr->name, NAME_MAX, "%s", channel_name);
+
+ ret = channel_ust_create(ustsession,
+ attr, ustsession->sock);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+ }
+
+ /* Get the newly created ust channel pointer */
+ ustchan = trace_ust_get_channel_by_name(channel_name,
+ ustsession);
+ if (ustchan == NULL) {
+ /* This sould not happen... */
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ ret = event_ust_enable_tracepoint(ustsession, ustchan, event);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ ustctl_wait_quiescent(ustsession->sock);
+ }
+ break;
+ }
+ case LTTNG_DOMAIN_UST_EXEC_NAME:
+ case LTTNG_DOMAIN_UST_PID:
+ case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN:
+ default:
+ /* TODO: UST other domains */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_ENABLE_ALL_EVENT processed by the client thread.
+ */
+static int cmd_enable_event_all(struct ltt_session *session, int domain,
+ char *channel_name, int event_type)
+{
+ int ret;
+ struct ltt_kernel_channel *kchan;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ /* This call will notify the kernel thread */
+ ret = channel_kernel_create(session->kernel_session, NULL,
+ kernel_poll_pipe[1]);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+ }
+
+ /* Get the newly created kernel channel pointer */
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ /* This sould not happen... */
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ switch (event_type) {
+ case LTTNG_KERNEL_SYSCALL:
+ ret = event_kernel_enable_all_syscalls(session->kernel_session,
+ kchan, kernel_tracer_fd);
+ break;
+ case LTTNG_KERNEL_TRACEPOINT:
+ /*
+ * This call enables all LTTNG_KERNEL_TRACEPOINTS and
+ * events already registered to the channel.
+ */
+ ret = event_kernel_enable_all_tracepoints(session->kernel_session,
+ kchan, kernel_tracer_fd);
+ break;
+ case LTTNG_KERNEL_ALL:
+ /* Enable syscalls and tracepoints */
+ ret = event_kernel_enable_all(session->kernel_session,
+ kchan, kernel_tracer_fd);
+ break;
+ default:
+ ret = LTTCOMM_KERN_ENABLE_FAIL;
+ goto error;
+ }
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_LIST_TRACEPOINTS processed by the client thread.
+ */
+static ssize_t cmd_list_tracepoints(int domain, struct lttng_event **events)
+{
+ int ret;
+ ssize_t nb_events = 0;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ nb_events = kernel_list_events(kernel_tracer_fd, events);
+ if (nb_events < 0) {
+ ret = LTTCOMM_KERN_LIST_FAIL;
+ goto error;
+ }
+ break;
+ default:
+ /* TODO: Userspace listing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ return nb_events;
+
+error:
+ /* Return negative value to differentiate return code */
+ return -ret;
+}
+
+/*
+ * Command LTTNG_START_TRACE processed by the client thread.
+ */
+static int cmd_start_trace(struct ltt_session *session)
+{
+ int ret;
+ struct ltt_kernel_session *ksession;
+ struct ltt_ust_session *ustsession;
+
+ /* Short cut */
+ ksession = session->kernel_session;
+
+ /* Kernel tracing */
+ if (ksession != NULL) {
+ struct ltt_kernel_channel *kchan;
+
+ /* Open kernel metadata */
+ if (ksession->metadata == NULL) {
+ ret = kernel_open_metadata(ksession, ksession->trace_path);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_META_FAIL;
+ goto error;
+ }
+ }
+
+ /* Open kernel metadata stream */
+ if (ksession->metadata_stream_fd == 0) {
+ ret = kernel_open_metadata_stream(ksession);
+ if (ret < 0) {
+ ERR("Kernel create metadata stream failed");
+ ret = LTTCOMM_KERN_STREAM_FAIL;
+ goto error;
+ }
+ }
+
+ /* For each channel */
+ cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) {
+ if (kchan->stream_count == 0) {
+ ret = kernel_open_channel_stream(kchan);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_STREAM_FAIL;
+ goto error;
+ }
+ /* Update the stream global counter */
+ ksession->stream_count_global += ret;
+ }
+ }
+
+ /* Setup kernel consumer socket and send fds to it */
+ ret = init_kernel_tracing(ksession);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_START_FAIL;
+ goto error;
+ }
+
+ /* This start the kernel tracing */
+ ret = kernel_start_session(ksession);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_START_FAIL;
+ goto error;
+ }
+
+ /* Quiescent wait after starting trace */
+ kernel_wait_quiescent(kernel_tracer_fd);
+ }
+
+ /* Start all UST traces */
+ cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) {
+ struct ltt_ust_channel *ustchan;
+
+ /* Open kernel metadata */
+ if (ustsession->metadata == NULL) {
+ struct lttng_ust_channel_attr ustattr;
+
+ /* Allocate UST metadata */
+ ustsession->metadata = trace_ust_create_metadata(ustsession->path);
+ if (ustsession->metadata == NULL) {
+ ret = LTTCOMM_UST_META_FAIL;
+ goto error;
+ }
+
+ ustattr.overwrite = ustsession->metadata->attr.overwrite;
+ ustattr.subbuf_size = ustsession->metadata->attr.subbuf_size;
+ ustattr.num_subbuf = ustsession->metadata->attr.num_subbuf;
+ ustattr.switch_timer_interval = ustsession->metadata->attr.switch_timer_interval;
+ ustattr.read_timer_interval = ustsession->metadata->attr.read_timer_interval;
+ ustattr.output = ustsession->metadata->attr.output;
+
+ /* UST tracer metadata creation */
+ ret = ustctl_open_metadata(ustsession->sock,
+ ustsession->handle, &ustattr,
+ &ustsession->metadata->obj);
+ if (ret < 0) {
+ ret = LTTCOMM_UST_META_FAIL;
+ goto error;
+ }
+ }
+
+ /* Open UST metadata stream */
+ if (ustsession->metadata->stream_obj == NULL) {
+ ret = ustctl_create_stream(ustsession->sock,
+ ustsession->metadata->obj,
+ &ustsession->metadata->stream_obj);
+ if (ret < 0) {
+ ERR("UST create metadata stream failed");
+ ret = LTTCOMM_UST_STREAM_FAIL;
+ goto error;
+ }
+ ret = asprintf(&ustsession->metadata->pathname, "%s/%s",
+ ustsession->path, "metadata");
+ if (ret < 0) {
+ perror("asprintf UST create stream");
+ goto error;
+ }
+ }
+
+ /* For each channel */
+ cds_list_for_each_entry(ustchan, &ustsession->channels.head, list) {
+ if (ustchan->stream_count == 0) {
+ struct ltt_ust_stream *ustream;
+
+ ustream = zmalloc(sizeof(*ustream));
+ if (!ustream) {
+ ret = LTTCOMM_UST_STREAM_FAIL;
+ goto error;
+ }
+ ret = ustctl_create_stream(ustsession->sock,
+ ustchan->obj, &ustream->obj);
+ if (ret < 0) {
+ ret = LTTCOMM_UST_STREAM_FAIL;
+ goto error;
+ }
+ ret = asprintf(&ustream->pathname, "%s/%s_%d",
+ ustchan->trace_path, ustchan->name,
+ ustchan->stream_count);
+ if (ret < 0) {
+ perror("asprintf UST create stream");
+ goto error;
+ }
+ cds_list_add(&ustream->list, &ustchan->stream_list.head);
+ ustchan->stream_count++;
+ }
+ }
+
+ /* Setup UST consumer socket and send fds to it */
+ ret = init_ust_tracing(ustsession);
+ if (ret < 0) {
+ ret = LTTCOMM_UST_START_FAIL;
+ goto error;
+ }
+
+ /* This start the UST tracing */
+ ret = ustctl_start_session(ustsession->sock, ustsession->handle);
+ if (ret < 0) {
+ ret = LTTCOMM_UST_START_FAIL;
+ goto error;
+ }
+
+ /* Quiescent wait after starting trace */
+ ustctl_wait_quiescent(ustsession->sock);
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_STOP_TRACE processed by the client thread.
+ */
+static int cmd_stop_trace(struct ltt_session *session)
+{
+ int ret;
+ struct ltt_kernel_channel *kchan;
+ struct ltt_kernel_session *ksession;
+ struct ltt_ust_session *ustsession;
+ struct ltt_ust_channel *ustchan;
+
+ /* Short cut */
+ ksession = session->kernel_session;
+
+ /* Kernel tracer */
+ if (ksession != NULL) {
+ DBG("Stop kernel tracing");
+
+ /* Flush all buffers before stopping */
+ ret = kernel_metadata_flush_buffer(ksession->metadata_stream_fd);
+ if (ret < 0) {
+ ERR("Kernel metadata flush failed");
+ }
+
+ cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) {
+ ret = kernel_flush_buffer(kchan);
+ if (ret < 0) {
+ ERR("Kernel flush buffer error");
+ }
+ }
+
+ ret = kernel_stop_session(ksession);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_STOP_FAIL;
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ }
+
+ /* Stop each UST session */
+ DBG("Stop UST tracing");
+ cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) {
+ /* Flush all buffers before stopping */
+ ret = ustctl_flush_buffer(ustsession->sock, ustsession->metadata->obj);
+ if (ret < 0) {
+ ERR("UST metadata flush failed");
+ }
+
+ cds_list_for_each_entry(ustchan, &ustsession->channels.head, list) {
+ ret = ustctl_flush_buffer(ustsession->sock, ustchan->obj);
+ if (ret < 0) {
+ ERR("UST flush buffer error");
+ }
+ }
+
+ ret = ustctl_stop_session(ustsession->sock, ustsession->handle);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_STOP_FAIL;
+ goto error;
+ }
+
+ ustctl_wait_quiescent(ustsession->sock);
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_CREATE_SESSION processed by the client thread.
+ */
+static int cmd_create_session(char *name, char *path)
+{
+ int ret;
+
+ ret = session_create(name, path);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_DESTROY_SESSION processed by the client thread.
+ */
+static int cmd_destroy_session(struct ltt_session *session, char *name)
+{
+ int ret;
+
+ /* Clean kernel session teardown */
+ teardown_kernel_session(session);
+
+ /*
+ * Must notify the kernel thread here to update it's poll setin order
+ * to remove the channel(s)' fd just destroyed.
+ */
+ ret = notify_thread_pipe(kernel_poll_pipe[1]);
+ if (ret < 0) {
+ perror("write kernel poll pipe");
+ }
+
+ ret = session_destroy(session);
+
+ return ret;
+}
+
+/*
+ * Command LTTNG_CALIBRATE processed by the client thread.
+ */
+static int cmd_calibrate(int domain, struct lttng_calibrate *calibrate)
+{
+ int ret;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ {
+ struct lttng_kernel_calibrate kcalibrate;
+
+ kcalibrate.type = calibrate->type;
+ ret = kernel_calibrate(kernel_tracer_fd, &kcalibrate);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_ENABLE_FAIL;
+ goto error;
+ }
+ break;
+ }
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_REGISTER_CONSUMER processed by the client thread.
+ */
+static int cmd_register_consumer(struct ltt_session *session, int domain,
+ char *sock_path)
+{
+ int ret, sock;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ /* Can't register a consumer if there is already one */
+ if (session->kernel_session->consumer_fd != 0) {
+ ret = LTTCOMM_KERN_CONSUMER_FAIL;
+ goto error;
+ }
+
+ sock = lttcomm_connect_unix_sock(sock_path);
+ if (sock < 0) {
+ ret = LTTCOMM_CONNECT_FAIL;
+ goto error;
+ }
+
+ session->kernel_session->consumer_fd = sock;
+ break;
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_LIST_DOMAINS processed by the client thread.
+ */
+static ssize_t cmd_list_domains(struct ltt_session *session,
+ struct lttng_domain **domains)
+{
+ int ret;
+ ssize_t nb_dom = 0;
+
+ if (session->kernel_session != NULL) {
+ nb_dom++;
+ }
+
+ /* TODO: User-space tracer domain support */
+
+ *domains = malloc(nb_dom * sizeof(struct lttng_domain));
+ if (*domains == NULL) {
+ ret = -LTTCOMM_FATAL;
+ goto error;
+ }
+
+ (*domains)[0].type = LTTNG_DOMAIN_KERNEL;
+
+ return nb_dom;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_LIST_CHANNELS processed by the client thread.
+ */
+static ssize_t cmd_list_channels(struct ltt_session *session,
+ struct lttng_channel **channels)
+{
+ int ret;
+ ssize_t nb_chan = 0;
+
+ if (session->kernel_session != NULL) {
+ nb_chan += session->kernel_session->channel_count;
+ }
+
+ *channels = malloc(nb_chan * sizeof(struct lttng_channel));
+ if (*channels == NULL) {
+ ret = -LTTCOMM_FATAL;
+ goto error;
+ }
+
+ list_lttng_channels(session, *channels);
+
+ /* TODO UST support */
+
+ return nb_chan;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_LIST_EVENTS processed by the client thread.
+ */
+static ssize_t cmd_list_events(struct ltt_session *session,
+ char *channel_name, struct lttng_event **events)
+{
+ int ret;
+ ssize_t nb_event = 0;
+ struct ltt_kernel_channel *kchan = NULL;
+
+ if (session->kernel_session != NULL) {
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ ret = -LTTCOMM_KERN_CHAN_NOT_FOUND;
+ goto error;
+ }
+ nb_event += kchan->event_count;
+ }
+
+ *events = malloc(nb_event * sizeof(struct lttng_event));
+ if (*events == NULL) {
+ ret = -LTTCOMM_FATAL;
+ goto error;
+ }
+
+ list_lttng_events(kchan, *events);
+
+ /* TODO: User-space tracer support */
+
+ return nb_event;
+
+error:
+ return ret;
+}
+
+/*
+ * Process the command requested by the lttng client within the command
+ * context structure. This function make sure that the return structure (llm)
+ * is set and ready for transmission before returning.
+ *
+ * Return any error encountered or 0 for success.
+ */
+static int process_client_msg(struct command_ctx *cmd_ctx)
+{
+ int ret = LTTCOMM_OK;
+ int need_tracing_session = 1;
+
+ DBG("Processing client command %d", cmd_ctx->lsm->cmd_type);
+
+ /*
+ * Check for command that don't needs to allocate a returned payload. We do
+ * this here so we don't have to make the call for no payload at each
+ * command.
+ */
+ switch(cmd_ctx->lsm->cmd_type) {
+ case LTTNG_LIST_SESSIONS:
+ case LTTNG_LIST_TRACEPOINTS:
+ case LTTNG_LIST_DOMAINS:
+ case LTTNG_LIST_CHANNELS:
+ case LTTNG_LIST_EVENTS:
+ break;
+ default:
+ /* Setup lttng message with no payload */
+ ret = setup_lttng_msg(cmd_ctx, 0);
+ if (ret < 0) {
+ /* This label does not try to unlock the session */
+ goto init_setup_error;
+ }
+ }
+
+ /* Commands that DO NOT need a session. */
+ switch (cmd_ctx->lsm->cmd_type) {
+ case LTTNG_CALIBRATE:
+ case LTTNG_CREATE_SESSION:
+ case LTTNG_LIST_SESSIONS:
+ case LTTNG_LIST_TRACEPOINTS:
+ need_tracing_session = 0;
+ break;
+ default:
+ DBG("Getting session %s by name", cmd_ctx->lsm->session.name);
+ session_lock_list();
+ cmd_ctx->session = session_find_by_name(cmd_ctx->lsm->session.name);
+ session_unlock_list();
+ if (cmd_ctx->session == NULL) {
+ if (cmd_ctx->lsm->session.name != NULL) {
+ ret = LTTCOMM_SESS_NOT_FOUND;
+ } else {
+ /* If no session name specified */