-/*
- * Join consumer thread
- */
-static int join_consumer_thread(struct consumer_data *consumer_data)
-{
- void *status;
-
- /* Consumer pid must be a real one. */
- if (consumer_data->pid > 0) {
- int ret;
- ret = kill(consumer_data->pid, SIGTERM);
- if (ret) {
- ERR("Error killing consumer daemon");
- return ret;
- }
- return pthread_join(consumer_data->thread, &status);
- } else {
- return 0;
- }
-}
-
-/*
- * Fork and exec a consumer daemon (consumerd).
- *
- * Return pid if successful else -1.
- */
-static pid_t spawn_consumerd(struct consumer_data *consumer_data)
-{
- int ret;
- pid_t pid;
- const char *consumer_to_use;
- const char *verbosity;
- struct stat st;
-
- DBG("Spawning consumerd");
-
- pid = fork();
- if (pid == 0) {
- /*
- * Exec consumerd.
- */
- if (opt_verbose_consumer) {
- verbosity = "--verbose";
- } else {
- verbosity = "--quiet";
- }
- switch (consumer_data->type) {
- case LTTNG_CONSUMER_KERNEL:
- /*
- * Find out which consumerd to execute. We will first try the
- * 64-bit path, then the sessiond's installation directory, and
- * fallback on the 32-bit one,
- */
- DBG3("Looking for a kernel consumer at these locations:");
- DBG3(" 1) %s", consumerd64_bin);
- DBG3(" 2) %s/%s", INSTALL_BIN_PATH, CONSUMERD_FILE);
- DBG3(" 3) %s", consumerd32_bin);
- if (stat(consumerd64_bin, &st) == 0) {
- DBG3("Found location #1");
- consumer_to_use = consumerd64_bin;
- } else if (stat(INSTALL_BIN_PATH "/" CONSUMERD_FILE, &st) == 0) {
- DBG3("Found location #2");
- consumer_to_use = INSTALL_BIN_PATH "/" CONSUMERD_FILE;
- } else if (stat(consumerd32_bin, &st) == 0) {
- DBG3("Found location #3");
- consumer_to_use = consumerd32_bin;
- } else {
- DBG("Could not find any valid consumerd executable");
- break;
- }
- DBG("Using kernel consumer at: %s", consumer_to_use);
- execl(consumer_to_use,
- "lttng-consumerd", verbosity, "-k",
- "--consumerd-cmd-sock", consumer_data->cmd_unix_sock_path,
- "--consumerd-err-sock", consumer_data->err_unix_sock_path,
- NULL);
- break;
- case LTTNG_CONSUMER64_UST:
- {
- char *tmpnew = NULL;
-
- if (consumerd64_libdir[0] != '\0') {
- char *tmp;
- size_t tmplen;
-
- tmp = getenv("LD_LIBRARY_PATH");
- if (!tmp) {
- tmp = "";
- }
- tmplen = strlen("LD_LIBRARY_PATH=")
- + strlen(consumerd64_libdir) + 1 /* : */ + strlen(tmp);
- tmpnew = zmalloc(tmplen + 1 /* \0 */);
- if (!tmpnew) {
- ret = -ENOMEM;
- goto error;
- }
- strcpy(tmpnew, "LD_LIBRARY_PATH=");
- strcat(tmpnew, consumerd64_libdir);
- if (tmp[0] != '\0') {
- strcat(tmpnew, ":");
- strcat(tmpnew, tmp);
- }
- ret = putenv(tmpnew);
- if (ret) {
- ret = -errno;
- goto error;
- }
- }
- DBG("Using 64-bit UST consumer at: %s", consumerd64_bin);
- ret = execl(consumerd64_bin, "lttng-consumerd", verbosity, "-u",
- "--consumerd-cmd-sock", consumer_data->cmd_unix_sock_path,
- "--consumerd-err-sock", consumer_data->err_unix_sock_path,
- NULL);
- if (consumerd64_libdir[0] != '\0') {
- free(tmpnew);
- }
- if (ret) {
- goto error;
- }
- break;
- }
- case LTTNG_CONSUMER32_UST:
- {
- char *tmpnew = NULL;
-
- if (consumerd32_libdir[0] != '\0') {
- char *tmp;
- size_t tmplen;
-
- tmp = getenv("LD_LIBRARY_PATH");
- if (!tmp) {
- tmp = "";
- }
- tmplen = strlen("LD_LIBRARY_PATH=")
- + strlen(consumerd32_libdir) + 1 /* : */ + strlen(tmp);
- tmpnew = zmalloc(tmplen + 1 /* \0 */);
- if (!tmpnew) {
- ret = -ENOMEM;
- goto error;
- }
- strcpy(tmpnew, "LD_LIBRARY_PATH=");
- strcat(tmpnew, consumerd32_libdir);
- if (tmp[0] != '\0') {
- strcat(tmpnew, ":");
- strcat(tmpnew, tmp);
- }
- ret = putenv(tmpnew);
- if (ret) {
- ret = -errno;
- goto error;
- }
- }
- DBG("Using 32-bit UST consumer at: %s", consumerd32_bin);
- ret = execl(consumerd32_bin, "lttng-consumerd", verbosity, "-u",
- "--consumerd-cmd-sock", consumer_data->cmd_unix_sock_path,
- "--consumerd-err-sock", consumer_data->err_unix_sock_path,
- NULL);
- if (consumerd32_libdir[0] != '\0') {
- free(tmpnew);
- }
- if (ret) {
- goto error;
- }
- break;
- }
- default:
- PERROR("unknown consumer type");
- exit(EXIT_FAILURE);
- }
- if (errno != 0) {
- PERROR("kernel start consumer exec");
- }
- exit(EXIT_FAILURE);
- } else if (pid > 0) {
- ret = pid;
- } else {
- PERROR("start consumer fork");
- ret = -errno;
- }
-error:
- return ret;
-}
-
-/*
- * Spawn the consumerd daemon and session daemon thread.
- */
-static int start_consumerd(struct consumer_data *consumer_data)
-{
- int ret;
-
- /*
- * Set the listen() state on the socket since there is a possible race
- * between the exec() of the consumer daemon and this call if place in the
- * consumer thread. See bug #366 for more details.
- */
- ret = lttcomm_listen_unix_sock(consumer_data->err_sock);
- if (ret < 0) {
- goto error;
- }
-
- pthread_mutex_lock(&consumer_data->pid_mutex);
- if (consumer_data->pid != 0) {
- pthread_mutex_unlock(&consumer_data->pid_mutex);
- goto end;
- }
-
- ret = spawn_consumerd(consumer_data);
- if (ret < 0) {
- ERR("Spawning consumerd failed");
- pthread_mutex_unlock(&consumer_data->pid_mutex);
- goto error;
- }
-
- /* Setting up the consumer_data pid */
- consumer_data->pid = ret;
- DBG2("Consumer pid %d", consumer_data->pid);
- pthread_mutex_unlock(&consumer_data->pid_mutex);
-
- DBG2("Spawning consumer control thread");
- ret = spawn_consumer_thread(consumer_data);
- if (ret < 0) {
- ERR("Fatal error spawning consumer control thread");
- goto error;
- }
-
-end:
- return 0;
-
-error:
- /* Cleanup already created socket on error. */
- if (consumer_data->err_sock >= 0) {
- int err;
-
- err = close(consumer_data->err_sock);
- if (err < 0) {
- PERROR("close consumer data error socket");
- }
- }
- return ret;
-}
-
-/*
- * Compute health status of each consumer. If one of them is zero (bad
- * state), we return 0.
- */
-static int check_consumer_health(void)
-{
- int ret;
-
- ret = health_check_state(&kconsumer_data.health) &&
- health_check_state(&ustconsumer32_data.health) &&
- health_check_state(&ustconsumer64_data.health);
-
- DBG3("Health consumer check %d", ret);
-
- return ret;
-}
-
-/*
- * Setup necessary data for kernel tracer action.
- */
-static int init_kernel_tracer(void)
-{
- int ret;
-
- /* Modprobe lttng kernel modules */
- ret = modprobe_lttng_control();
- if (ret < 0) {
- goto error;
- }
-
- /* Open debugfs lttng */
- kernel_tracer_fd = open(module_proc_lttng, O_RDWR);
- if (kernel_tracer_fd < 0) {
- DBG("Failed to open %s", module_proc_lttng);
- ret = -1;
- goto error_open;
- }
-
- /* Validate kernel version */
- ret = kernel_validate_version(kernel_tracer_fd);
- if (ret < 0) {
- goto error_version;
- }
-
- ret = modprobe_lttng_data();
- if (ret < 0) {
- goto error_modules;
- }
-
- DBG("Kernel tracer fd %d", kernel_tracer_fd);
- return 0;
-
-error_version:
- modprobe_remove_lttng_control();
- ret = close(kernel_tracer_fd);
- if (ret) {
- PERROR("close");
- }
- kernel_tracer_fd = -1;
- return LTTNG_ERR_KERN_VERSION;
-
-error_modules:
- ret = close(kernel_tracer_fd);
- if (ret) {
- PERROR("close");
- }
-
-error_open:
- modprobe_remove_lttng_control();
-
-error:
- WARN("No kernel tracer available");
- kernel_tracer_fd = -1;
- if (!is_root) {
- return LTTNG_ERR_NEED_ROOT_SESSIOND;
- } else {
- return LTTNG_ERR_KERN_NA;
- }
-}
-
-
-/*
- * Copy consumer output from the tracing session to the domain session. The
- * function also applies the right modification on a per domain basis for the
- * trace files destination directory.
- */
-static int copy_session_consumer(int domain, struct ltt_session *session)
-{
- int ret;
- const char *dir_name;
- struct consumer_output *consumer;
-
- assert(session);
- assert(session->consumer);
-
- switch (domain) {
- case LTTNG_DOMAIN_KERNEL:
- DBG3("Copying tracing session consumer output in kernel session");
- /*
- * XXX: We should audit the session creation and what this function
- * does "extra" in order to avoid a destroy since this function is used
- * in the domain session creation (kernel and ust) only. Same for UST
- * domain.
- */
- if (session->kernel_session->consumer) {
- consumer_destroy_output(session->kernel_session->consumer);
- }
- session->kernel_session->consumer =
- consumer_copy_output(session->consumer);
- /* Ease our life a bit for the next part */
- consumer = session->kernel_session->consumer;
- dir_name = DEFAULT_KERNEL_TRACE_DIR;
- break;
- case LTTNG_DOMAIN_UST:
- DBG3("Copying tracing session consumer output in UST session");
- if (session->ust_session->consumer) {
- consumer_destroy_output(session->ust_session->consumer);
- }
- session->ust_session->consumer =
- consumer_copy_output(session->consumer);
- /* Ease our life a bit for the next part */
- consumer = session->ust_session->consumer;
- dir_name = DEFAULT_UST_TRACE_DIR;
- break;
- default:
- ret = LTTNG_ERR_UNKNOWN_DOMAIN;
- goto error;
- }
-
- /* Append correct directory to subdir */
- strncat(consumer->subdir, dir_name,
- sizeof(consumer->subdir) - strlen(consumer->subdir) - 1);
- DBG3("Copy session consumer subdir %s", consumer->subdir);
-
- ret = LTTNG_OK;
-
-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;
-
- assert(session);
- assert(domain);
- assert(session->consumer);
-
- switch (domain->type) {
- case LTTNG_DOMAIN_UST:
- break;
- default:
- ERR("Unknown UST domain on create session %d", domain->type);
- ret = LTTNG_ERR_UNKNOWN_DOMAIN;
- goto error;
- }
-
- DBG("Creating UST session");
-
- lus = trace_ust_create_session(session->path, session->id, domain);
- if (lus == NULL) {
- ret = LTTNG_ERR_UST_SESS_FAIL;
- goto error;
- }
-
- lus->uid = session->uid;
- lus->gid = session->gid;
- session->ust_session = lus;
-
- /* Copy session output to the newly created UST session */
- ret = copy_session_consumer(domain->type, session);
- if (ret != LTTNG_OK) {
- goto error;
- }
-
- return LTTNG_OK;
-
-error:
- free(lus);
- session->ust_session = NULL;
- 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 = LTTNG_ERR_KERN_SESS_FAIL;
- goto error;
- }
-
- /* Code flow safety */
- assert(session->kernel_session);
-
- /* Copy session output to the newly created Kernel session */
- ret = copy_session_consumer(LTTNG_DOMAIN_KERNEL, session);
- if (ret != LTTNG_OK) {
- goto error;
- }
-
- /* Create directory(ies) on local filesystem. */
- if (session->kernel_session->consumer->type == CONSUMER_DST_LOCAL &&
- strlen(session->kernel_session->consumer->dst.trace_path) > 0) {
- ret = run_as_mkdir_recursive(
- session->kernel_session->consumer->dst.trace_path,
- S_IRWXU | S_IRWXG, session->uid, session->gid);
- if (ret < 0) {
- if (ret != -EEXIST) {
- ERR("Trace directory creation error");
- goto error;
- }
- }
- }
-
- session->kernel_session->uid = session->uid;
- session->kernel_session->gid = session->gid;
-
- return LTTNG_OK;
-
-error:
- trace_kernel_destroy_session(session->kernel_session);
- session->kernel_session = NULL;
- return ret;
-}
-
-/*
- * Count number of session permitted by uid/gid.
- */
-static unsigned int lttng_sessions_count(uid_t uid, gid_t gid)