+ default:
+ goto error;
+ }
+
+ DBG("Creating UST session");
+
+ lus = trace_ust_create_session(session->path, domain->attr.pid, domain);
+ if (lus == NULL) {
+ ret = LTTCOMM_UST_SESS_FAIL;
+ goto error;
+ }
+
+ ret = mkdir_recursive(lus->path, S_IRWXU | S_IRWXG,
+ geteuid(), allowed_group());
+ if (ret < 0) {
+ if (ret != -EEXIST) {
+ ERR("Trace directory creation error");
+ ret = LTTCOMM_UST_SESS_FAIL;
+ goto error;
+ }
+ }
+
+ /* Create session on the UST tracer */
+ ret = ustctl_create_session(app->sock, lus);
+ if (ret < 0) {
+ ret = LTTCOMM_UST_SESS_FAIL;
+ goto error;
+ }
+
+ cds_list_add(&lus->list, &session->ust_session_list.head);
+ session->ust_session_list.count++;
+
+ return LTTCOMM_OK;
+
+error:
+ free(lus);
+ return ret;
+}
+
+/*
+ * Create a kernel tracer session then create the default channel.
+ */
+static int create_kernel_session(struct ltt_session *session)
+{
+ int ret;
+
+ DBG("Creating kernel session");
+
+ ret = kernel_create_session(session, kernel_tracer_fd);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_SESS_FAIL;
+ goto error;
+ }
+
+ /* Set kernel consumer socket fd */
+ if (kconsumerd_cmd_sock) {
+ session->kernel_session->consumer_fd = kconsumerd_cmd_sock;
+ }
+
+ ret = mkdir_recursive(session->kernel_session->trace_path,
+ S_IRWXU | S_IRWXG, geteuid(), allowed_group());
+ if (ret < 0) {
+ if (ret != -EEXIST) {
+ ERR("Trace directory creation error");
+ goto error;
+ }
+ }
+
+error:
+ 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().
+ */
+static void list_lttng_sessions(struct lttng_session *sessions)
+{
+ int i = 0;
+ struct ltt_session *session;
+
+ DBG("Getting all available session");
+ /*
+ * Iterate over session list and append data after the control struct in
+ * the buffer.
+ */
+ cds_list_for_each_entry(session, &session_list_ptr->head, list) {
+ strncpy(sessions[i].path, session->path, PATH_MAX);
+ sessions[i].path[PATH_MAX - 1] = '\0';
+ strncpy(sessions[i].name, session->name, NAME_MAX);
+ sessions[i].name[NAME_MAX - 1] = '\0';
+ i++;
+ }
+}
+
+/*
+ * Fill lttng_channel array of all channels.
+ */
+static void list_lttng_channels(struct ltt_session *session,
+ struct lttng_channel *channels)
+{
+ int i = 0;
+ struct ltt_kernel_channel *kchan;
+
+ DBG("Listing channels for session %s", session->name);
+
+ /* Kernel channels */
+ if (session->kernel_session != NULL) {
+ cds_list_for_each_entry(kchan,
+ &session->kernel_session->channel_list.head, list) {
+ /* Copy lttng_channel struct to array */
+ memcpy(&channels[i], kchan->channel, sizeof(struct lttng_channel));
+ channels[i].enabled = kchan->enabled;
+ i++;
+ }
+ }
+
+ /* TODO: Missing UST listing */
+}
+
+/*
+ * Fill lttng_event array of all events in the channel.
+ */
+static void list_lttng_events(struct ltt_kernel_channel *kchan,
+ struct lttng_event *events)
+{
+ /*
+ * TODO: This is ONLY kernel. Need UST support.
+ */
+ int i = 0;
+ struct ltt_kernel_event *event;
+
+ DBG("Listing events for channel %s", kchan->channel->name);
+
+ /* Kernel channels */
+ cds_list_for_each_entry(event, &kchan->events_list.head , list) {
+ strncpy(events[i].name, event->event->name, LTTNG_SYMBOL_NAME_LEN);
+ events[i].name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
+ events[i].enabled = event->enabled;
+ switch (event->event->instrumentation) {
+ case LTTNG_KERNEL_TRACEPOINT:
+ events[i].type = LTTNG_EVENT_TRACEPOINT;
+ break;
+ case LTTNG_KERNEL_KPROBE:
+ case LTTNG_KERNEL_KRETPROBE:
+ events[i].type = LTTNG_EVENT_PROBE;
+ memcpy(&events[i].attr.probe, &event->event->u.kprobe,
+ sizeof(struct lttng_kernel_kprobe));
+ break;
+ case LTTNG_KERNEL_FUNCTION:
+ events[i].type = LTTNG_EVENT_FUNCTION;
+ memcpy(&events[i].attr.ftrace, &event->event->u.ftrace,
+ sizeof(struct lttng_kernel_function));
+ break;
+ case LTTNG_KERNEL_NOOP:
+ events[i].type = LTTNG_EVENT_NOOP;
+ break;
+ case LTTNG_KERNEL_SYSCALL:
+ events[i].type = LTTNG_EVENT_SYSCALL;
+ break;
+ }
+ i++;
+ }
+}
+
+/*
+ * Command LTTNG_DISABLE_CHANNEL processed by the client thread.
+ */
+static int cmd_disable_channel(struct ltt_session *session,
+ int domain, char *channel_name)
+{
+ int ret;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ ret = channel_kernel_disable(session->kernel_session,
+ channel_name);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ 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;
+}
+
+/*
+ * 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;
+
+ 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_PID:
+ {
+ struct ltt_ust_event *uevent, *new_uevent;
+ struct ltt_ust_session *usess;
+ struct ltt_ust_channel *uchan, *app_chan;
+ struct ltt_traceable_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 = traceable_app_get_by_pid(domain->attr.pid);
+ if (app == NULL) {
+ ret = LTTCOMM_APP_NOT_FOUND;
+ goto error;
+ }
+
+ uchan = trace_ust_get_channel_by_name(attr->name, usess);
+ if (uchan == NULL) {
+ ret = channel_ust_create(usess, attr, app->sock);
+ } else {
+ ret = channel_ust_enable(usess, uchan, app->sock);
+ }
+
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ /*TODO: This should be put in an external function */
+
+ /* Copy UST channel to add to the traceable app */
+ uchan = trace_ust_get_channel_by_name(attr->name, usess);
+ if (uchan == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ app_chan = trace_ust_create_channel(attr, session->path);
+ if (app_chan == NULL) {
+ PERROR("malloc ltt_ust_channel");
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ memcpy(app_chan, uchan, sizeof(struct ltt_ust_channel));
+ CDS_INIT_LIST_HEAD(&app_chan->events.head);
+
+ cds_list_for_each_entry(uevent, &uchan->events.head, list) {
+ new_uevent = malloc(sizeof(struct ltt_ust_event));
+ if (new_uevent == NULL) {
+ PERROR("malloc ltt_ust_event");
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ memcpy(new_uevent, uevent, sizeof(struct ltt_ust_event));
+ cds_list_add(&new_uevent->list, &app_chan->events.head);
+ app_chan->events.count++;
+ }
+
+ /* Add channel to traceable_app */
+ cds_list_add(&app_chan->list, &app->channels.head);
+ app->channels.count++;
+
+ DBG("UST channel %s created for app sock %d with pid %d",
+ attr->name, app->sock, domain->attr.pid);
+ break;
+ }
+ 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;
+ 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(session->kernel_session, kchan, event_name);
+ 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_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;
+ default:
+ /* TODO: Userspace tracing */
+ 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 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;
+ }
+
+ ret = event_kernel_enable(session->kernel_session, kchan, event);
+ 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_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;
+ }
+
+ if (event_type == LTTNG_KERNEL_SYSCALL) {
+ ret = event_kernel_enable_syscalls(session->kernel_session,
+ kchan, kernel_tracer_fd);
+ } else {
+ /*
+ * This call enables all LTTNG_KERNEL_TRACEPOINTS and events
+ * already registered to the channel.
+ */
+ ret = event_kernel_enable_all(session->kernel_session,
+ kchan, kernel_tracer_fd);
+ }
+
+ 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_channel *kchan;
+ struct ltt_kernel_session *ksession;
+
+ /* Short cut */
+ ksession = session->kernel_session;
+
+ /* Kernel tracing */
+ if (ksession != NULL) {
+ /* 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);