+ if (kconsumerd_pid != 0) {
+ ret = kill(kconsumerd_pid, SIGTERM);
+ if (ret) {
+ ERR("Error killing kconsumerd");
+ return ret;
+ }
+ return pthread_join(kconsumerd_thread, &status);
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * Fork and exec a kernel consumer daemon (kconsumerd).
+ *
+ * Return pid if successful else -1.
+ */
+static pid_t spawn_kconsumerd(void)
+{
+ int ret;
+ pid_t pid;
+ const char *verbosity;
+
+ DBG("Spawning kconsumerd");
+
+ pid = fork();
+ if (pid == 0) {
+ /*
+ * Exec kconsumerd.
+ */
+ if (opt_verbose > 1 || opt_verbose_kconsumerd) {
+ verbosity = "--verbose";
+ } else {
+ verbosity = "--quiet";
+ }
+ execl(INSTALL_BIN_PATH "/ltt-kconsumerd",
+ "ltt-kconsumerd", verbosity, NULL);
+ if (errno != 0) {
+ perror("kernel start consumer exec");
+ }
+ exit(EXIT_FAILURE);
+ } else if (pid > 0) {
+ ret = pid;
+ goto error;
+ } else {
+ perror("kernel start consumer fork");
+ ret = -errno;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Spawn the kconsumerd daemon and session daemon thread.
+ */
+static int start_kconsumerd(void)
+{
+ int ret;
+
+ pthread_mutex_lock(&kconsumerd_pid_mutex);
+ if (kconsumerd_pid != 0) {
+ pthread_mutex_unlock(&kconsumerd_pid_mutex);
+ goto end;
+ }
+
+ ret = spawn_kconsumerd();
+ if (ret < 0) {
+ ERR("Spawning kconsumerd failed");
+ pthread_mutex_unlock(&kconsumerd_pid_mutex);
+ goto error;
+ }
+
+ /* Setting up the global kconsumerd_pid */
+ kconsumerd_pid = ret;
+ DBG2("Kconsumerd pid %d", kconsumerd_pid);
+ pthread_mutex_unlock(&kconsumerd_pid_mutex);
+
+ DBG2("Spawning kconsumerd thread");
+ ret = spawn_kconsumerd_thread();
+ if (ret < 0) {
+ ERR("Fatal error spawning kconsumerd thread");
+ goto error;
+ }
+
+end:
+ return 0;
+
+error:
+ return ret;
+}
+
+/*
+ * modprobe_kernel_modules
+ */
+static int modprobe_kernel_modules(void)
+{
+ int ret = 0, i;
+ char modprobe[256];
+
+ for (i = 0; i < ARRAY_SIZE(kernel_modules_list); i++) {
+ ret = snprintf(modprobe, sizeof(modprobe),
+ "/sbin/modprobe %s%s",
+ kernel_modules_list[i].required ? "" : "--quiet ",
+ kernel_modules_list[i].name);
+ if (ret < 0) {
+ perror("snprintf modprobe");
+ goto error;
+ }
+ modprobe[sizeof(modprobe) - 1] = '\0';
+ ret = system(modprobe);
+ if (ret == -1) {
+ ERR("Unable to launch modprobe for module %s",
+ kernel_modules_list[i].name);
+ } else if (kernel_modules_list[i].required
+ && WEXITSTATUS(ret) != 0) {
+ ERR("Unable to load module %s",
+ kernel_modules_list[i].name);
+ } else {
+ DBG("Modprobe successfully %s",
+ kernel_modules_list[i].name);
+ }
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * mount_debugfs
+ */
+static int mount_debugfs(char *path)
+{
+ int ret;
+ char *type = "debugfs";
+
+ ret = mkdir_recursive(path, S_IRWXU | S_IRWXG, geteuid(), getegid());
+ if (ret < 0) {
+ PERROR("Cannot create debugfs path");
+ goto error;
+ }
+
+ ret = mount(type, path, type, 0, NULL);
+ if (ret < 0) {
+ PERROR("Cannot mount debugfs");
+ goto error;
+ }
+
+ DBG("Mounted debugfs successfully at %s", path);
+
+error:
+ return ret;
+}
+
+/*
+ * Setup necessary data for kernel tracer action.
+ */
+static void init_kernel_tracer(void)
+{
+ int ret;
+ char *proc_mounts = "/proc/mounts";
+ char line[256];
+ char *debugfs_path = NULL, *lttng_path = NULL;
+ FILE *fp;
+
+ /* Detect debugfs */
+ fp = fopen(proc_mounts, "r");
+ if (fp == NULL) {
+ ERR("Unable to probe %s", proc_mounts);
+ goto error;
+ }
+
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ if (strstr(line, "debugfs") != NULL) {
+ /* Remove first string */
+ strtok(line, " ");
+ /* Dup string here so we can reuse line later on */
+ debugfs_path = strdup(strtok(NULL, " "));
+ DBG("Got debugfs path : %s", debugfs_path);
+ break;
+ }
+ }
+
+ fclose(fp);
+
+ /* Mount debugfs if needded */
+ if (debugfs_path == NULL) {
+ ret = asprintf(&debugfs_path, "/mnt/debugfs");
+ if (ret < 0) {
+ perror("asprintf debugfs path");
+ goto error;
+ }
+ ret = mount_debugfs(debugfs_path);
+ if (ret < 0) {
+ perror("Cannot mount debugfs");
+ goto error;
+ }
+ }
+
+ /* Modprobe lttng kernel modules */
+ ret = modprobe_kernel_modules();
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* Setup lttng kernel path */
+ ret = asprintf(<tng_path, "%s/lttng", debugfs_path);
+ if (ret < 0) {
+ perror("asprintf lttng path");
+ goto error;
+ }
+
+ /* Open debugfs lttng */
+ kernel_tracer_fd = open(lttng_path, O_RDWR);
+ if (kernel_tracer_fd < 0) {
+ DBG("Failed to open %s", lttng_path);
+ goto error;
+ }
+
+ free(lttng_path);
+ free(debugfs_path);
+ DBG("Kernel tracer fd %d", kernel_tracer_fd);
+ return;
+
+error:
+ if (lttng_path) {
+ free(lttng_path);
+ }
+ if (debugfs_path) {
+ free(debugfs_path);
+ }
+ WARN("No kernel tracer available");
+ kernel_tracer_fd = 0;
+ return;
+}
+
+/*
+ * Init tracing by creating trace directory and sending fds kernel consumer.
+ */
+static int init_kernel_tracing(struct ltt_kernel_session *session)
+{
+ int ret = 0;
+
+ if (session->kconsumer_fds_sent == 0) {
+ /*
+ * Assign default kernel consumer socket if no consumer assigned to the
+ * kernel session. At this point, it's NOT suppose to be 0 but this is
+ * an extra security check.
+ */
+ if (session->consumer_fd == 0) {
+ session->consumer_fd = kconsumerd_cmd_sock;
+ }
+
+ ret = send_kconsumerd_fds(session);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_CONSUMER_FAIL;
+ goto error;
+ }
+
+ session->kconsumer_fds_sent = 1;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Create an UST session and add it to the session ust list.
+ */
+static int create_ust_session(struct ltt_session *session,
+ struct lttng_domain *domain)
+{
+ int ret;
+ struct ltt_ust_session *lus = NULL;
+ struct ust_app *app;
+
+ switch (domain->type) {
+ case LTTNG_DOMAIN_UST_PID:
+ app = ust_app_get_by_pid(domain->attr.pid);
+ if (app == NULL) {
+ ret = LTTCOMM_APP_NOT_FOUND;
+ goto error;
+ }
+ break;
+ default:
+ ret = LTTCOMM_UNKNOWN_DOMAIN;
+ 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;
+ case LTTNG_KERNEL_ALL:
+ assert(0);
+ 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;
+}
+
+/*
+ * 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_name(attr->name, usess);
+ 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;
+ }
+
+ /* Add channel to the ust app channel list */
+ cds_list_add(&new_chan->list, &app->channels.head);
+ app->channels.count++;
+
+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:
+ {
+ 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);
+ 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_tracepoint(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;
+ struct lttng_channel *attr;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ 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;