X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fclient.c;fp=src%2Fbin%2Flttng-sessiond%2Fclient.c;h=0000000000000000000000000000000000000000;hp=ed9f2af3e4134bef0ad57ba799296053598a8d36;hb=7966af5763c4aaca39df9bbfa9277ff15715c720;hpb=3a5f70173aa04d11ccb22694d5d31a702cad33ab diff --git a/src/bin/lttng-sessiond/client.c b/src/bin/lttng-sessiond/client.c deleted file mode 100644 index ed9f2af3e..000000000 --- a/src/bin/lttng-sessiond/client.c +++ /dev/null @@ -1,2906 +0,0 @@ -/* - * Copyright (C) 2011 David Goulet - * Copyright (C) 2011 Mathieu Desnoyers - * Copyright (C) 2013 Jérémie Galarneau - * - * SPDX-License-Identifier: GPL-2.0-only - * - */ - -#include "common/buffer-view.h" -#include "common/compat/socket.h" -#include "common/dynamic-array.h" -#include "common/dynamic-buffer.h" -#include "common/fd-handle.h" -#include "common/payload-view.h" -#include "common/payload.h" -#include "common/sessiond-comm/sessiond-comm.h" -#include "lttng/lttng-error.h" -#include "lttng/tracker.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "agent-thread.h" -#include "clear.h" -#include "client.h" -#include "cmd.h" -#include "health-sessiond.h" -#include "kernel.h" -#include "lttng-sessiond.h" -#include "manage-consumer.h" -#include "save.h" -#include "testpoint.h" -#include "utils.h" - -static bool is_root; - -static struct thread_state { - sem_t ready; - bool running; - int client_sock; -} thread_state; - -static void set_thread_status(bool running) -{ - DBG("Marking client thread's state as %s", running ? "running" : "error"); - thread_state.running = running; - sem_post(&thread_state.ready); -} - -static bool wait_thread_status(void) -{ - DBG("Waiting for client thread to be ready"); - sem_wait(&thread_state.ready); - if (thread_state.running) { - DBG("Client thread is ready"); - } else { - ERR("Initialization of client thread failed"); - } - - return thread_state.running; -} - -/* - * Setup the outgoing data buffer for the response (llm) by allocating the - * right amount of memory and copying the original information from the lsm - * structure. - * - * Return 0 on success, negative value on error. - */ -static int setup_lttng_msg(struct command_ctx *cmd_ctx, - const void *payload_buf, size_t payload_len, - const void *cmd_header_buf, size_t cmd_header_len) -{ - int ret = 0; - const size_t header_len = sizeof(struct lttcomm_lttng_msg); - const size_t total_msg_size = header_len + cmd_header_len + payload_len; - const struct lttcomm_lttng_msg llm = { - .cmd_type = cmd_ctx->lsm.cmd_type, - .pid = cmd_ctx->lsm.domain.attr.pid, - .cmd_header_size = cmd_header_len, - .data_size = payload_len, - }; - - ret = lttng_dynamic_buffer_set_size(&cmd_ctx->reply_payload.buffer, 0); - if (ret) { - goto end; - } - - lttng_dynamic_pointer_array_clear(&cmd_ctx->reply_payload._fd_handles); - - cmd_ctx->lttng_msg_size = total_msg_size; - - /* Append reply header. */ - ret = lttng_dynamic_buffer_append( - &cmd_ctx->reply_payload.buffer, &llm, sizeof(llm)); - if (ret) { - goto end; - } - - /* Append command header. */ - if (cmd_header_len) { - ret = lttng_dynamic_buffer_append( - &cmd_ctx->reply_payload.buffer, cmd_header_buf, - cmd_header_len); - if (ret) { - goto end; - } - } - - /* Append payload. */ - if (payload_len) { - ret = lttng_dynamic_buffer_append( - &cmd_ctx->reply_payload.buffer, payload_buf, - payload_len); - if (ret) { - goto end; - } - } - -end: - return ret; -} - -static int setup_empty_lttng_msg(struct command_ctx *cmd_ctx) -{ - int ret; - const struct lttcomm_lttng_msg llm = {}; - - ret = lttng_dynamic_buffer_set_size(&cmd_ctx->reply_payload.buffer, 0); - if (ret) { - goto end; - } - - /* Append place-holder reply header. */ - ret = lttng_dynamic_buffer_append( - &cmd_ctx->reply_payload.buffer, &llm, sizeof(llm)); - if (ret) { - goto end; - } - - cmd_ctx->lttng_msg_size = sizeof(llm); -end: - return ret; -} - -static void update_lttng_msg(struct command_ctx *cmd_ctx, size_t cmd_header_len, - size_t payload_len) -{ - const size_t header_len = sizeof(struct lttcomm_lttng_msg); - const size_t total_msg_size = header_len + cmd_header_len + payload_len; - const struct lttcomm_lttng_msg llm = { - .cmd_type = cmd_ctx->lsm.cmd_type, - .pid = cmd_ctx->lsm.domain.attr.pid, - .cmd_header_size = cmd_header_len, - .data_size = payload_len, - }; - struct lttcomm_lttng_msg *p_llm; - - LTTNG_ASSERT(cmd_ctx->reply_payload.buffer.size >= sizeof(llm)); - - p_llm = (typeof(p_llm)) cmd_ctx->reply_payload.buffer.data; - - /* Update existing header. */ - memcpy(p_llm, &llm, sizeof(llm)); - - cmd_ctx->lttng_msg_size = total_msg_size; -} - -/* - * Start the thread_manage_consumer. This must be done after a lttng-consumerd - * exec or it will fail. - */ -static int spawn_consumer_thread(struct consumer_data *consumer_data) -{ - return launch_consumer_management_thread(consumer_data) ? 0 : -1; -} - -/* - * 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 (the_config.verbose_consumer) { - verbosity = "--verbose"; - } else if (lttng_opt_quiet) { - verbosity = "--quiet"; - } else { - verbosity = ""; - } - - 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", the_config.consumerd64_bin_path.value ? : "NULL"); - DBG3(" 2) %s/%s", INSTALL_BIN_PATH, DEFAULT_CONSUMERD_FILE); - DBG3(" 3) %s", the_config.consumerd32_bin_path.value ? : "NULL"); - if (stat(the_config.consumerd64_bin_path.value, &st) == 0) { - DBG3("Found location #1"); - consumer_to_use = the_config.consumerd64_bin_path.value; - } else if (stat(INSTALL_BIN_PATH "/" DEFAULT_CONSUMERD_FILE, &st) == 0) { - DBG3("Found location #2"); - consumer_to_use = INSTALL_BIN_PATH "/" DEFAULT_CONSUMERD_FILE; - } else if (the_config.consumerd32_bin_path.value && - stat(the_config.consumerd32_bin_path.value, &st) == 0) { - DBG3("Found location #3"); - consumer_to_use = the_config.consumerd32_bin_path.value; - } else { - DBG("Could not find any valid consumerd executable"); - ret = -EINVAL; - goto error; - } - DBG("Using kernel consumer at: %s", consumer_to_use); - (void) 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, - "--group", - the_config.tracing_group_name.value, - NULL); - break; - case LTTNG_CONSUMER64_UST: - { - if (the_config.consumerd64_lib_dir.value) { - const char *tmp; - size_t tmplen; - char *tmpnew; - - tmp = lttng_secure_getenv("LD_LIBRARY_PATH"); - if (!tmp) { - tmp = ""; - } - tmplen = strlen(the_config.consumerd64_lib_dir.value) + 1 /* : */ + strlen(tmp); - tmpnew = zmalloc(tmplen + 1 /* \0 */); - if (!tmpnew) { - ret = -ENOMEM; - goto error; - } - strcat(tmpnew, the_config.consumerd64_lib_dir.value); - if (tmp[0] != '\0') { - strcat(tmpnew, ":"); - strcat(tmpnew, tmp); - } - ret = setenv("LD_LIBRARY_PATH", tmpnew, 1); - free(tmpnew); - if (ret) { - ret = -errno; - goto error; - } - } - DBG("Using 64-bit UST consumer at: %s", - the_config.consumerd64_bin_path.value); - (void) execl(the_config.consumerd64_bin_path.value, - "lttng-consumerd", verbosity, "-u", - "--consumerd-cmd-sock", - consumer_data->cmd_unix_sock_path, - "--consumerd-err-sock", - consumer_data->err_unix_sock_path, - "--group", - the_config.tracing_group_name.value, - NULL); - break; - } - case LTTNG_CONSUMER32_UST: - { - if (the_config.consumerd32_lib_dir.value) { - const char *tmp; - size_t tmplen; - char *tmpnew; - - tmp = lttng_secure_getenv("LD_LIBRARY_PATH"); - if (!tmp) { - tmp = ""; - } - tmplen = strlen(the_config.consumerd32_lib_dir.value) + 1 /* : */ + strlen(tmp); - tmpnew = zmalloc(tmplen + 1 /* \0 */); - if (!tmpnew) { - ret = -ENOMEM; - goto error; - } - strcat(tmpnew, the_config.consumerd32_lib_dir.value); - if (tmp[0] != '\0') { - strcat(tmpnew, ":"); - strcat(tmpnew, tmp); - } - ret = setenv("LD_LIBRARY_PATH", tmpnew, 1); - free(tmpnew); - if (ret) { - ret = -errno; - goto error; - } - } - DBG("Using 32-bit UST consumer at: %s", - the_config.consumerd32_bin_path.value); - (void) execl(the_config.consumerd32_bin_path.value, - "lttng-consumerd", verbosity, "-u", - "--consumerd-cmd-sock", - consumer_data->cmd_unix_sock_path, - "--consumerd-err-sock", - consumer_data->err_unix_sock_path, - "--group", - the_config.tracing_group_name.value, - NULL); - break; - } - default: - ERR("unknown consumer type"); - errno = 0; - } - if (errno != 0) { - PERROR("Consumer execl()"); - } - /* Reaching this point, we got a failure on our execl(). */ - 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 sockets 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; -} - -/* - * 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. - * - * Should *NOT* be called with RCU read-side lock held. - */ -static int copy_session_consumer(int domain, struct ltt_session *session) -{ - int ret; - const char *dir_name; - struct consumer_output *consumer; - - LTTNG_ASSERT(session); - LTTNG_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_output_put(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_JUL: - case LTTNG_DOMAIN_LOG4J: - case LTTNG_DOMAIN_PYTHON: - case LTTNG_DOMAIN_UST: - DBG3("Copying tracing session consumer output in UST session"); - if (session->ust_session->consumer) { - consumer_output_put(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 */ - ret = lttng_strncpy(consumer->domain_subdir, dir_name, - sizeof(consumer->domain_subdir)); - if (ret) { - ret = LTTNG_ERR_UNK; - goto error; - } - DBG3("Copy session consumer subdir %s", consumer->domain_subdir); - ret = LTTNG_OK; - -error: - return ret; -} - -/* - * Create an UST session and add it to the session ust list. - * - * Should *NOT* be called with RCU read-side lock held. - */ -static int create_ust_session(struct ltt_session *session, - const struct lttng_domain *domain) -{ - int ret; - struct ltt_ust_session *lus = NULL; - - LTTNG_ASSERT(session); - LTTNG_ASSERT(domain); - LTTNG_ASSERT(session->consumer); - - switch (domain->type) { - case LTTNG_DOMAIN_JUL: - case LTTNG_DOMAIN_LOG4J: - case LTTNG_DOMAIN_PYTHON: - 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->id); - if (lus == NULL) { - ret = LTTNG_ERR_UST_SESS_FAIL; - goto error; - } - - lus->uid = session->uid; - lus->gid = session->gid; - lus->output_traces = session->output_traces; - lus->snapshot_mode = session->snapshot_mode; - lus->live_timer_interval = session->live_timer; - session->ust_session = lus; - if (session->shm_path[0]) { - strncpy(lus->root_shm_path, session->shm_path, - sizeof(lus->root_shm_path)); - lus->root_shm_path[sizeof(lus->root_shm_path) - 1] = '\0'; - strncpy(lus->shm_path, session->shm_path, - sizeof(lus->shm_path)); - lus->shm_path[sizeof(lus->shm_path) - 1] = '\0'; - strncat(lus->shm_path, "/ust", - sizeof(lus->shm_path) - strlen(lus->shm_path) - 1); - } - /* 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); - if (ret < 0) { - ret = LTTNG_ERR_KERN_SESS_FAIL; - goto error_create; - } - - /* Code flow safety */ - LTTNG_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; - } - - session->kernel_session->uid = session->uid; - session->kernel_session->gid = session->gid; - session->kernel_session->output_traces = session->output_traces; - session->kernel_session->snapshot_mode = session->snapshot_mode; - session->kernel_session->is_live_session = session->live_timer != 0; - - return LTTNG_OK; - -error: - trace_kernel_destroy_session(session->kernel_session); - session->kernel_session = NULL; -error_create: - return ret; -} - -/* - * Count number of session permitted by uid/gid. - */ -static unsigned int lttng_sessions_count(uid_t uid, gid_t gid) -{ - unsigned int i = 0; - struct ltt_session *session; - const struct ltt_session_list *session_list = session_get_list(); - - DBG("Counting number of available session for UID %d", uid); - cds_list_for_each_entry(session, &session_list->head, list) { - if (!session_get(session)) { - continue; - } - session_lock(session); - /* Only count the sessions the user can control. */ - if (session_access_ok(session, uid) && - !session->destroyed) { - i++; - } - session_unlock(session); - session_put(session); - } - return i; -} - -static int receive_userspace_probe(struct command_ctx *cmd_ctx, int sock, - int *sock_error, struct lttng_event *event) -{ - int fd = -1, ret; - struct lttng_userspace_probe_location *probe_location; - struct lttng_payload probe_location_payload; - struct fd_handle *handle = NULL; - - /* - * Create a payload to store the serialized version of the probe - * location. - */ - lttng_payload_init(&probe_location_payload); - - ret = lttng_dynamic_buffer_set_size(&probe_location_payload.buffer, - cmd_ctx->lsm.u.enable.userspace_probe_location_len); - if (ret) { - ret = LTTNG_ERR_NOMEM; - goto error; - } - - /* - * Receive the probe location. - */ - ret = lttcomm_recv_unix_sock(sock, probe_location_payload.buffer.data, - probe_location_payload.buffer.size); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - /* - * Receive the file descriptor to the target binary from the client. - */ - DBG("Receiving userspace probe target FD from client ..."); - ret = lttcomm_recv_fds_unix_sock(sock, &fd, 1); - if (ret <= 0) { - DBG("Nothing recv() from client userspace probe fd... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - handle = fd_handle_create(fd); - if (!handle) { - ret = LTTNG_ERR_NOMEM; - goto error; - } - - /* Transferred to the handle. */ - fd = -1; - - ret = lttng_payload_push_fd_handle(&probe_location_payload, handle); - if (ret) { - ERR("Failed to add userspace probe file descriptor to payload"); - ret = LTTNG_ERR_NOMEM; - goto error; - } - - fd_handle_put(handle); - handle = NULL; - - { - struct lttng_payload_view view = lttng_payload_view_from_payload( - &probe_location_payload, 0, -1); - - /* Extract the probe location from the serialized version. */ - ret = lttng_userspace_probe_location_create_from_payload( - &view, &probe_location); - } - if (ret < 0) { - WARN("Failed to create a userspace probe location from the received buffer"); - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - /* Attach the probe location to the event. */ - ret = lttng_event_set_userspace_probe_location(event, probe_location); - if (ret) { - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - -error: - if (fd >= 0) { - if (close(fd)) { - PERROR("Failed to close userspace probe location binary fd"); - } - } - - fd_handle_put(handle); - lttng_payload_reset(&probe_location_payload); - return ret; -} - -static enum lttng_error_code receive_lttng_trigger(struct command_ctx *cmd_ctx, - int sock, - int *sock_error, - struct lttng_trigger **_trigger) -{ - int ret; - size_t trigger_len; - ssize_t sock_recv_len; - enum lttng_error_code ret_code; - struct lttng_payload trigger_payload; - struct lttng_trigger *trigger = NULL; - - lttng_payload_init(&trigger_payload); - trigger_len = (size_t) cmd_ctx->lsm.u.trigger.length; - ret = lttng_dynamic_buffer_set_size( - &trigger_payload.buffer, trigger_len); - if (ret) { - ret_code = LTTNG_ERR_NOMEM; - goto end; - } - - sock_recv_len = lttcomm_recv_unix_sock( - sock, trigger_payload.buffer.data, trigger_len); - if (sock_recv_len < 0 || sock_recv_len != trigger_len) { - ERR("Failed to receive trigger in command payload"); - *sock_error = 1; - ret_code = LTTNG_ERR_INVALID_PROTOCOL; - goto end; - } - - /* Receive fds, if any. */ - if (cmd_ctx->lsm.fd_count > 0) { - sock_recv_len = lttcomm_recv_payload_fds_unix_sock( - sock, cmd_ctx->lsm.fd_count, &trigger_payload); - if (sock_recv_len > 0 && - sock_recv_len != cmd_ctx->lsm.fd_count * sizeof(int)) { - ERR("Failed to receive all file descriptors for trigger in command payload: expected fd count = %u, ret = %d", - cmd_ctx->lsm.fd_count, (int) ret); - ret_code = LTTNG_ERR_INVALID_PROTOCOL; - *sock_error = 1; - goto end; - } else if (sock_recv_len <= 0) { - ERR("Failed to receive file descriptors for trigger in command payload: expected fd count = %u, ret = %d", - cmd_ctx->lsm.fd_count, (int) ret); - ret_code = LTTNG_ERR_FATAL; - *sock_error = 1; - goto end; - } - } - - /* Deserialize trigger. */ - { - struct lttng_payload_view view = - lttng_payload_view_from_payload( - &trigger_payload, 0, -1); - - if (lttng_trigger_create_from_payload(&view, &trigger) != - trigger_len) { - ERR("Invalid trigger received as part of command payload"); - ret_code = LTTNG_ERR_INVALID_TRIGGER; - lttng_trigger_put(trigger); - goto end; - } - } - - *_trigger = trigger; - ret_code = LTTNG_OK; - -end: - lttng_payload_reset(&trigger_payload); - return ret_code; -} - -static enum lttng_error_code receive_lttng_error_query(struct command_ctx *cmd_ctx, - int sock, - int *sock_error, - struct lttng_error_query **_query) -{ - int ret; - size_t query_len; - ssize_t sock_recv_len; - enum lttng_error_code ret_code; - struct lttng_payload query_payload; - struct lttng_error_query *query = NULL; - - lttng_payload_init(&query_payload); - query_len = (size_t) cmd_ctx->lsm.u.error_query.length; - ret = lttng_dynamic_buffer_set_size(&query_payload.buffer, query_len); - if (ret) { - ret_code = LTTNG_ERR_NOMEM; - goto end; - } - - sock_recv_len = lttcomm_recv_unix_sock( - sock, query_payload.buffer.data, query_len); - if (sock_recv_len < 0 || sock_recv_len != query_len) { - ERR("Failed to receive error query in command payload"); - *sock_error = 1; - ret_code = LTTNG_ERR_INVALID_PROTOCOL; - goto end; - } - - /* Receive fds, if any. */ - if (cmd_ctx->lsm.fd_count > 0) { - sock_recv_len = lttcomm_recv_payload_fds_unix_sock( - sock, cmd_ctx->lsm.fd_count, &query_payload); - if (sock_recv_len > 0 && - sock_recv_len != cmd_ctx->lsm.fd_count * sizeof(int)) { - ERR("Failed to receive all file descriptors for error query in command payload: expected fd count = %u, ret = %d", - cmd_ctx->lsm.fd_count, (int) ret); - ret_code = LTTNG_ERR_INVALID_PROTOCOL; - *sock_error = 1; - goto end; - } else if (sock_recv_len <= 0) { - ERR("Failed to receive file descriptors for error query in command payload: expected fd count = %u, ret = %d", - cmd_ctx->lsm.fd_count, (int) ret); - ret_code = LTTNG_ERR_FATAL; - *sock_error = 1; - goto end; - } - } - - /* Deserialize error query. */ - { - struct lttng_payload_view view = - lttng_payload_view_from_payload( - &query_payload, 0, -1); - - if (lttng_error_query_create_from_payload(&view, &query) != - query_len) { - ERR("Invalid error query received as part of command payload"); - ret_code = LTTNG_ERR_INVALID_PROTOCOL; - goto end; - } - } - - *_query = query; - ret_code = LTTNG_OK; - -end: - lttng_payload_reset(&query_payload); - return ret_code; -} - -/* - * Version of setup_lttng_msg() without command header. - */ -static int setup_lttng_msg_no_cmd_header(struct command_ctx *cmd_ctx, - void *payload_buf, size_t payload_len) -{ - return setup_lttng_msg(cmd_ctx, payload_buf, payload_len, NULL, 0); -} - -/* - * Check if the current kernel tracer supports the session rotation feature. - * Return 1 if it does, 0 otherwise. - */ -static int check_rotate_compatible(void) -{ - int ret = 1; - - if (the_kernel_tracer_version.major != 2 || - the_kernel_tracer_version.minor < 11) { - DBG("Kernel tracer version is not compatible with the rotation feature"); - ret = 0; - } - - return ret; -} - -/* - * Send data on a unix socket using the liblttsessiondcomm API. - * - * Return lttcomm error code. - */ -static int send_unix_sock(int sock, struct lttng_payload_view *view) -{ - int ret; - const int fd_count = lttng_payload_view_get_fd_handle_count(view); - - /* Check valid length */ - if (view->buffer.size == 0) { - ret = -1; - goto end; - } - - ret = lttcomm_send_unix_sock( - sock, view->buffer.data, view->buffer.size); - if (ret < 0) { - goto end; - } - - if (fd_count > 0) { - ret = lttcomm_send_payload_view_fds_unix_sock(sock, view); - if (ret < 0) { - goto end; - } - } - -end: - 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. - * - * "sock" is only used for special-case var. len data. - * A command may assume the ownership of the socket, in which case its value - * should be set to -1. - * - * Should *NOT* be called with RCU read-side lock held. - */ -static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, - int *sock_error) -{ - int ret = LTTNG_OK; - bool need_tracing_session = true; - bool need_domain; - bool need_consumerd; - - DBG("Processing client command '%s\' (%d)", - lttcomm_sessiond_command_str(cmd_ctx->lsm.cmd_type), - cmd_ctx->lsm.cmd_type); - - LTTNG_ASSERT(!rcu_read_ongoing()); - - *sock_error = 0; - - switch (cmd_ctx->lsm.cmd_type) { - case LTTNG_CREATE_SESSION_EXT: - case LTTNG_DESTROY_SESSION: - case LTTNG_LIST_SESSIONS: - case LTTNG_LIST_DOMAINS: - case LTTNG_START_TRACE: - case LTTNG_STOP_TRACE: - case LTTNG_DATA_PENDING: - case LTTNG_SNAPSHOT_ADD_OUTPUT: - case LTTNG_SNAPSHOT_DEL_OUTPUT: - case LTTNG_SNAPSHOT_LIST_OUTPUT: - case LTTNG_SNAPSHOT_RECORD: - case LTTNG_SAVE_SESSION: - case LTTNG_SET_SESSION_SHM_PATH: - case LTTNG_REGENERATE_METADATA: - case LTTNG_REGENERATE_STATEDUMP: - case LTTNG_ROTATE_SESSION: - case LTTNG_ROTATION_GET_INFO: - case LTTNG_ROTATION_SET_SCHEDULE: - case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: - case LTTNG_CLEAR_SESSION: - case LTTNG_LIST_TRIGGERS: - case LTTNG_EXECUTE_ERROR_QUERY: - need_domain = false; - break; - default: - need_domain = true; - } - - /* Needs a functioning consumerd? */ - switch (cmd_ctx->lsm.cmd_type) { - case LTTNG_REGISTER_TRIGGER: - case LTTNG_UNREGISTER_TRIGGER: - case LTTNG_EXECUTE_ERROR_QUERY: - need_consumerd = false; - break; - default: - need_consumerd = true; - break; - } - - if (the_config.no_kernel && need_domain && - cmd_ctx->lsm.domain.type == LTTNG_DOMAIN_KERNEL) { - if (!is_root) { - ret = LTTNG_ERR_NEED_ROOT_SESSIOND; - } else { - ret = LTTNG_ERR_KERN_NA; - } - goto error; - } - - /* Deny register consumer if we already have a spawned consumer. */ - if (cmd_ctx->lsm.cmd_type == LTTNG_REGISTER_CONSUMER) { - pthread_mutex_lock(&the_kconsumer_data.pid_mutex); - if (the_kconsumer_data.pid > 0) { - ret = LTTNG_ERR_KERN_CONSUMER_FAIL; - pthread_mutex_unlock(&the_kconsumer_data.pid_mutex); - goto error; - } - pthread_mutex_unlock(&the_kconsumer_data.pid_mutex); - } - - /* - * 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_TRACEPOINT_FIELDS: - case LTTNG_LIST_DOMAINS: - case LTTNG_LIST_CHANNELS: - case LTTNG_LIST_EVENTS: - case LTTNG_LIST_SYSCALLS: - case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: - case LTTNG_PROCESS_ATTR_TRACKER_GET_POLICY: - case LTTNG_PROCESS_ATTR_TRACKER_GET_INCLUSION_SET: - case LTTNG_DATA_PENDING: - case LTTNG_ROTATE_SESSION: - case LTTNG_ROTATION_GET_INFO: - case LTTNG_REGISTER_TRIGGER: - case LTTNG_LIST_TRIGGERS: - case LTTNG_EXECUTE_ERROR_QUERY: - break; - default: - /* Setup lttng message with no payload */ - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, NULL, 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_CREATE_SESSION_EXT: - case LTTNG_LIST_SESSIONS: - case LTTNG_LIST_TRACEPOINTS: - case LTTNG_LIST_SYSCALLS: - case LTTNG_LIST_TRACEPOINT_FIELDS: - case LTTNG_SAVE_SESSION: - case LTTNG_REGISTER_TRIGGER: - case LTTNG_UNREGISTER_TRIGGER: - case LTTNG_LIST_TRIGGERS: - case LTTNG_EXECUTE_ERROR_QUERY: - need_tracing_session = false; - break; - default: - DBG("Getting session %s by name", cmd_ctx->lsm.session.name); - /* - * We keep the session list lock across _all_ commands - * for now, because the per-session lock does not - * handle teardown properly. - */ - session_lock_list(); - cmd_ctx->session = session_find_by_name(cmd_ctx->lsm.session.name); - if (cmd_ctx->session == NULL) { - ret = LTTNG_ERR_SESS_NOT_FOUND; - goto error; - } else { - /* Acquire lock for the session */ - session_lock(cmd_ctx->session); - } - break; - } - - /* - * Commands that need a valid session but should NOT create one if none - * exists. Instead of creating one and destroying it when the command is - * handled, process that right before so we save some round trip in useless - * code path. - */ - switch (cmd_ctx->lsm.cmd_type) { - case LTTNG_DISABLE_CHANNEL: - case LTTNG_DISABLE_EVENT: - switch (cmd_ctx->lsm.domain.type) { - case LTTNG_DOMAIN_KERNEL: - if (!cmd_ctx->session->kernel_session) { - ret = LTTNG_ERR_NO_CHANNEL; - goto error; - } - break; - case LTTNG_DOMAIN_JUL: - case LTTNG_DOMAIN_LOG4J: - case LTTNG_DOMAIN_PYTHON: - case LTTNG_DOMAIN_UST: - if (!cmd_ctx->session->ust_session) { - ret = LTTNG_ERR_NO_CHANNEL; - goto error; - } - break; - default: - ret = LTTNG_ERR_UNKNOWN_DOMAIN; - goto error; - } - default: - break; - } - - if (!need_domain) { - goto skip_domain; - } - - /* - * Check domain type for specific "pre-action". - */ - switch (cmd_ctx->lsm.domain.type) { - case LTTNG_DOMAIN_KERNEL: - if (!is_root) { - ret = LTTNG_ERR_NEED_ROOT_SESSIOND; - goto error; - } - - /* Kernel tracer check */ - if (!kernel_tracer_is_initialized()) { - /* Basically, load kernel tracer modules */ - ret = init_kernel_tracer(); - if (ret != 0) { - goto error; - } - } - - /* Consumer is in an ERROR state. Report back to client */ - if (need_consumerd && uatomic_read(&the_kernel_consumerd_state) == - CONSUMER_ERROR) { - ret = LTTNG_ERR_NO_KERNCONSUMERD; - goto error; - } - - /* Need a session for kernel command */ - if (need_tracing_session) { - if (cmd_ctx->session->kernel_session == NULL) { - ret = create_kernel_session(cmd_ctx->session); - if (ret != LTTNG_OK) { - ret = LTTNG_ERR_KERN_SESS_FAIL; - goto error; - } - } - - /* Start the kernel consumer daemon */ - pthread_mutex_lock(&the_kconsumer_data.pid_mutex); - if (the_kconsumer_data.pid == 0 && - cmd_ctx->lsm.cmd_type != LTTNG_REGISTER_CONSUMER) { - pthread_mutex_unlock(&the_kconsumer_data.pid_mutex); - ret = start_consumerd(&the_kconsumer_data); - if (ret < 0) { - ret = LTTNG_ERR_KERN_CONSUMER_FAIL; - goto error; - } - uatomic_set(&the_kernel_consumerd_state, CONSUMER_STARTED); - } else { - pthread_mutex_unlock(&the_kconsumer_data.pid_mutex); - } - - /* - * The consumer was just spawned so we need to add the socket to - * the consumer output of the session if exist. - */ - ret = consumer_create_socket(&the_kconsumer_data, - cmd_ctx->session->kernel_session->consumer); - if (ret < 0) { - goto error; - } - } - - break; - case LTTNG_DOMAIN_JUL: - case LTTNG_DOMAIN_LOG4J: - case LTTNG_DOMAIN_PYTHON: - if (!agent_tracing_is_enabled()) { - ret = LTTNG_ERR_AGENT_TRACING_DISABLED; - goto error; - } - /* Fallthrough */ - case LTTNG_DOMAIN_UST: - { - if (!ust_app_supported()) { - ret = LTTNG_ERR_NO_UST; - goto error; - } - - /* Consumer is in an ERROR state. Report back to client */ - if (need_consumerd && - uatomic_read(&the_ust_consumerd_state) == - CONSUMER_ERROR) { - ret = LTTNG_ERR_NO_USTCONSUMERD; - goto error; - } - - if (need_tracing_session) { - /* Create UST session if none exist. */ - if (cmd_ctx->session->ust_session == NULL) { - ret = create_ust_session(cmd_ctx->session, - ALIGNED_CONST_PTR(cmd_ctx->lsm.domain)); - if (ret != LTTNG_OK) { - goto error; - } - } - - /* Start the UST consumer daemons */ - /* 64-bit */ - pthread_mutex_lock(&the_ustconsumer64_data.pid_mutex); - if (the_config.consumerd64_bin_path.value && - the_ustconsumer64_data.pid == 0 && - cmd_ctx->lsm.cmd_type != LTTNG_REGISTER_CONSUMER) { - pthread_mutex_unlock(&the_ustconsumer64_data.pid_mutex); - ret = start_consumerd(&the_ustconsumer64_data); - if (ret < 0) { - ret = LTTNG_ERR_UST_CONSUMER64_FAIL; - uatomic_set(&the_ust_consumerd64_fd, -EINVAL); - goto error; - } - - uatomic_set(&the_ust_consumerd64_fd, the_ustconsumer64_data.cmd_sock); - uatomic_set(&the_ust_consumerd_state, CONSUMER_STARTED); - } else { - pthread_mutex_unlock(&the_ustconsumer64_data.pid_mutex); - } - - /* - * Setup socket for consumer 64 bit. No need for atomic access - * since it was set above and can ONLY be set in this thread. - */ - ret = consumer_create_socket(&the_ustconsumer64_data, - cmd_ctx->session->ust_session->consumer); - if (ret < 0) { - goto error; - } - - /* 32-bit */ - pthread_mutex_lock(&the_ustconsumer32_data.pid_mutex); - if (the_config.consumerd32_bin_path.value && - the_ustconsumer32_data.pid == 0 && - cmd_ctx->lsm.cmd_type != LTTNG_REGISTER_CONSUMER) { - pthread_mutex_unlock(&the_ustconsumer32_data.pid_mutex); - ret = start_consumerd(&the_ustconsumer32_data); - if (ret < 0) { - ret = LTTNG_ERR_UST_CONSUMER32_FAIL; - uatomic_set(&the_ust_consumerd32_fd, -EINVAL); - goto error; - } - - uatomic_set(&the_ust_consumerd32_fd, the_ustconsumer32_data.cmd_sock); - uatomic_set(&the_ust_consumerd_state, CONSUMER_STARTED); - } else { - pthread_mutex_unlock(&the_ustconsumer32_data.pid_mutex); - } - - /* - * Setup socket for consumer 32 bit. No need for atomic access - * since it was set above and can ONLY be set in this thread. - */ - ret = consumer_create_socket(&the_ustconsumer32_data, - cmd_ctx->session->ust_session->consumer); - if (ret < 0) { - goto error; - } - } - break; - } - default: - break; - } -skip_domain: - - /* Validate consumer daemon state when start/stop trace command */ - if (cmd_ctx->lsm.cmd_type == LTTNG_START_TRACE || - cmd_ctx->lsm.cmd_type == LTTNG_STOP_TRACE) { - switch (cmd_ctx->lsm.domain.type) { - case LTTNG_DOMAIN_NONE: - break; - case LTTNG_DOMAIN_JUL: - case LTTNG_DOMAIN_LOG4J: - case LTTNG_DOMAIN_PYTHON: - case LTTNG_DOMAIN_UST: - if (uatomic_read(&the_ust_consumerd_state) != CONSUMER_STARTED) { - ret = LTTNG_ERR_NO_USTCONSUMERD; - goto error; - } - break; - case LTTNG_DOMAIN_KERNEL: - if (uatomic_read(&the_kernel_consumerd_state) != CONSUMER_STARTED) { - ret = LTTNG_ERR_NO_KERNCONSUMERD; - goto error; - } - break; - default: - ret = LTTNG_ERR_UNKNOWN_DOMAIN; - goto error; - } - } - - /* - * Check that the UID matches that of the tracing session. - * The root user can interact with all sessions. - */ - if (need_tracing_session) { - if (!session_access_ok(cmd_ctx->session, - LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds)) || - cmd_ctx->session->destroyed) { - ret = LTTNG_ERR_EPERM; - goto error; - } - } - - /* - * Send relayd information to consumer as soon as we have a domain and a - * session defined. - */ - if (cmd_ctx->session && need_domain) { - /* - * Setup relayd if not done yet. If the relayd information was already - * sent to the consumer, this call will gracefully return. - */ - ret = cmd_setup_relayd(cmd_ctx->session); - if (ret != LTTNG_OK) { - goto error; - } - } - - /* Process by command type */ - switch (cmd_ctx->lsm.cmd_type) { - case LTTNG_ADD_CONTEXT: - { - /* - * An LTTNG_ADD_CONTEXT command might have a supplementary - * payload if the context being added is an application context. - */ - if (cmd_ctx->lsm.u.context.ctx.ctx == - LTTNG_EVENT_CONTEXT_APP_CONTEXT) { - char *provider_name = NULL, *context_name = NULL; - size_t provider_name_len = - cmd_ctx->lsm.u.context.provider_name_len; - size_t context_name_len = - cmd_ctx->lsm.u.context.context_name_len; - - if (provider_name_len == 0 || context_name_len == 0) { - /* - * Application provider and context names MUST - * be provided. - */ - ret = -LTTNG_ERR_INVALID; - goto error; - } - - provider_name = zmalloc(provider_name_len + 1); - if (!provider_name) { - ret = -LTTNG_ERR_NOMEM; - goto error; - } - cmd_ctx->lsm.u.context.ctx.u.app_ctx.provider_name = - provider_name; - - context_name = zmalloc(context_name_len + 1); - if (!context_name) { - ret = -LTTNG_ERR_NOMEM; - goto error_add_context; - } - cmd_ctx->lsm.u.context.ctx.u.app_ctx.ctx_name = - context_name; - - ret = lttcomm_recv_unix_sock(*sock, provider_name, - provider_name_len); - if (ret < 0) { - goto error_add_context; - } - - ret = lttcomm_recv_unix_sock(*sock, context_name, - context_name_len); - if (ret < 0) { - goto error_add_context; - } - } - - /* - * cmd_add_context assumes ownership of the provider and context - * names. - */ - ret = cmd_add_context(cmd_ctx->session, - cmd_ctx->lsm.domain.type, - cmd_ctx->lsm.u.context.channel_name, - ALIGNED_CONST_PTR(cmd_ctx->lsm.u.context.ctx), - the_kernel_poll_pipe[1]); - - cmd_ctx->lsm.u.context.ctx.u.app_ctx.provider_name = NULL; - cmd_ctx->lsm.u.context.ctx.u.app_ctx.ctx_name = NULL; -error_add_context: - free(cmd_ctx->lsm.u.context.ctx.u.app_ctx.provider_name); - free(cmd_ctx->lsm.u.context.ctx.u.app_ctx.ctx_name); - if (ret < 0) { - goto error; - } - break; - } - case LTTNG_DISABLE_CHANNEL: - { - ret = cmd_disable_channel(cmd_ctx->session, cmd_ctx->lsm.domain.type, - cmd_ctx->lsm.u.disable.channel_name); - break; - } - case LTTNG_DISABLE_EVENT: - { - - /* - * FIXME: handle filter; for now we just receive the filter's - * bytecode along with the filter expression which are sent by - * liblttng-ctl and discard them. - * - * This fixes an issue where the client may block while sending - * the filter payload and encounter an error because the session - * daemon closes the socket without ever handling this data. - */ - size_t count = cmd_ctx->lsm.u.disable.expression_len + - cmd_ctx->lsm.u.disable.bytecode_len; - - if (count) { - char data[LTTNG_FILTER_MAX_LEN]; - - DBG("Discarding disable event command payload of size %zu", count); - while (count) { - ret = lttcomm_recv_unix_sock(*sock, data, - count > sizeof(data) ? sizeof(data) : count); - if (ret < 0) { - goto error; - } - - count -= (size_t) ret; - } - } - ret = cmd_disable_event(cmd_ctx->session, cmd_ctx->lsm.domain.type, - cmd_ctx->lsm.u.disable.channel_name, - ALIGNED_CONST_PTR(cmd_ctx->lsm.u.disable.event)); - break; - } - case LTTNG_ENABLE_CHANNEL: - { - cmd_ctx->lsm.u.channel.chan.attr.extended.ptr = - (struct lttng_channel_extended *) &cmd_ctx->lsm.u.channel.extended; - ret = cmd_enable_channel(cmd_ctx->session, - ALIGNED_CONST_PTR(cmd_ctx->lsm.domain), - ALIGNED_CONST_PTR(cmd_ctx->lsm.u.channel.chan), - the_kernel_poll_pipe[1]); - break; - } - case LTTNG_PROCESS_ATTR_TRACKER_ADD_INCLUDE_VALUE: - case LTTNG_PROCESS_ATTR_TRACKER_REMOVE_INCLUDE_VALUE: - { - struct lttng_dynamic_buffer payload; - struct lttng_buffer_view payload_view; - const bool add_value = - cmd_ctx->lsm.cmd_type == - LTTNG_PROCESS_ATTR_TRACKER_ADD_INCLUDE_VALUE; - const size_t name_len = - cmd_ctx->lsm.u.process_attr_tracker_add_remove_include_value - .name_len; - const enum lttng_domain_type domain_type = - (enum lttng_domain_type) - cmd_ctx->lsm.domain.type; - const enum lttng_process_attr process_attr = - (enum lttng_process_attr) cmd_ctx->lsm.u - .process_attr_tracker_add_remove_include_value - .process_attr; - const enum lttng_process_attr_value_type value_type = - (enum lttng_process_attr_value_type) cmd_ctx - ->lsm.u - .process_attr_tracker_add_remove_include_value - .value_type; - struct process_attr_value *value; - enum lttng_error_code ret_code; - long login_name_max; - - login_name_max = sysconf(_SC_LOGIN_NAME_MAX); - if (login_name_max < 0) { - PERROR("Failed to get _SC_LOGIN_NAME_MAX system configuration"); - ret = LTTNG_ERR_INVALID; - goto error; - } - - /* Receive remaining variable length payload if applicable. */ - if (name_len > login_name_max) { - /* - * POSIX mandates user and group names that are at least - * 8 characters long. Note that although shadow-utils - * (useradd, groupaadd, etc.) use 32 chars as their - * limit (from bits/utmp.h, UT_NAMESIZE), - * LOGIN_NAME_MAX is defined to 256. - */ - ERR("Rejecting process attribute tracker value %s as the provided exceeds the maximal allowed length: argument length = %zu, maximal length = %ld", - add_value ? "addition" : "removal", - name_len, login_name_max); - ret = LTTNG_ERR_INVALID; - goto error; - } - - lttng_dynamic_buffer_init(&payload); - if (name_len != 0) { - /* - * Receive variable payload for user/group name - * arguments. - */ - ret = lttng_dynamic_buffer_set_size(&payload, name_len); - if (ret) { - ERR("Failed to allocate buffer to receive payload of %s process attribute tracker value argument", - add_value ? "add" : "remove"); - ret = LTTNG_ERR_NOMEM; - goto error_add_remove_tracker_value; - } - - ret = lttcomm_recv_unix_sock( - *sock, payload.data, name_len); - if (ret <= 0) { - ERR("Failed to receive payload of %s process attribute tracker value argument", - add_value ? "add" : "remove"); - *sock_error = 1; - ret = LTTNG_ERR_INVALID_PROTOCOL; - goto error_add_remove_tracker_value; - } - } - - payload_view = lttng_buffer_view_from_dynamic_buffer( - &payload, 0, name_len); - if (name_len > 0 && !lttng_buffer_view_is_valid(&payload_view)) { - ret = LTTNG_ERR_INVALID_PROTOCOL; - goto error_add_remove_tracker_value; - } - - /* - * Validate the value type and domains are legal for the process - * attribute tracker that is specified and convert the value to - * add/remove to the internal sessiond representation. - */ - ret_code = process_attr_value_from_comm(domain_type, - process_attr, value_type, - &cmd_ctx->lsm.u.process_attr_tracker_add_remove_include_value - .integral_value, - &payload_view, &value); - if (ret_code != LTTNG_OK) { - ret = ret_code; - goto error_add_remove_tracker_value; - } - - if (add_value) { - ret = cmd_process_attr_tracker_inclusion_set_add_value( - cmd_ctx->session, domain_type, - process_attr, value); - } else { - ret = cmd_process_attr_tracker_inclusion_set_remove_value( - cmd_ctx->session, domain_type, - process_attr, value); - } - process_attr_value_destroy(value); - error_add_remove_tracker_value: - lttng_dynamic_buffer_reset(&payload); - break; - } - case LTTNG_PROCESS_ATTR_TRACKER_GET_POLICY: - { - enum lttng_tracking_policy tracking_policy; - const enum lttng_domain_type domain_type = - (enum lttng_domain_type) - cmd_ctx->lsm.domain.type; - const enum lttng_process_attr process_attr = - (enum lttng_process_attr) cmd_ctx->lsm.u - .process_attr_tracker_get_tracking_policy - .process_attr; - - ret = cmd_process_attr_tracker_get_tracking_policy( - cmd_ctx->session, domain_type, process_attr, - &tracking_policy); - if (ret != LTTNG_OK) { - goto error; - } - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, - &(uint32_t){tracking_policy}, sizeof(uint32_t)); - if (ret < 0) { - ret = LTTNG_ERR_NOMEM; - goto error; - } - ret = LTTNG_OK; - break; - } - case LTTNG_PROCESS_ATTR_TRACKER_SET_POLICY: - { - const enum lttng_tracking_policy tracking_policy = - (enum lttng_tracking_policy) cmd_ctx->lsm.u - .process_attr_tracker_set_tracking_policy - .tracking_policy; - const enum lttng_domain_type domain_type = - (enum lttng_domain_type) - cmd_ctx->lsm.domain.type; - const enum lttng_process_attr process_attr = - (enum lttng_process_attr) cmd_ctx->lsm.u - .process_attr_tracker_set_tracking_policy - .process_attr; - - ret = cmd_process_attr_tracker_set_tracking_policy( - cmd_ctx->session, domain_type, process_attr, - tracking_policy); - if (ret != LTTNG_OK) { - goto error; - } - break; - } - case LTTNG_PROCESS_ATTR_TRACKER_GET_INCLUSION_SET: - { - struct lttng_process_attr_values *values; - struct lttng_dynamic_buffer reply; - const enum lttng_domain_type domain_type = - (enum lttng_domain_type) - cmd_ctx->lsm.domain.type; - const enum lttng_process_attr process_attr = - (enum lttng_process_attr) cmd_ctx->lsm.u - .process_attr_tracker_get_inclusion_set - .process_attr; - - ret = cmd_process_attr_tracker_get_inclusion_set( - cmd_ctx->session, domain_type, process_attr, - &values); - if (ret != LTTNG_OK) { - goto error; - } - - lttng_dynamic_buffer_init(&reply); - ret = lttng_process_attr_values_serialize(values, &reply); - if (ret < 0) { - goto error_tracker_get_inclusion_set; - } - - ret = setup_lttng_msg_no_cmd_header( - cmd_ctx, reply.data, reply.size); - if (ret < 0) { - ret = LTTNG_ERR_NOMEM; - goto error_tracker_get_inclusion_set; - } - ret = LTTNG_OK; - - error_tracker_get_inclusion_set: - lttng_process_attr_values_destroy(values); - lttng_dynamic_buffer_reset(&reply); - break; - } - case LTTNG_ENABLE_EVENT: - { - struct lttng_event *ev = NULL; - struct lttng_event_exclusion *exclusion = NULL; - struct lttng_bytecode *bytecode = NULL; - char *filter_expression = NULL; - - /* Handle exclusion events and receive it from the client. */ - if (cmd_ctx->lsm.u.enable.exclusion_count > 0) { - size_t count = cmd_ctx->lsm.u.enable.exclusion_count; - - exclusion = zmalloc(sizeof(struct lttng_event_exclusion) + - (count * LTTNG_SYMBOL_NAME_LEN)); - if (!exclusion) { - ret = LTTNG_ERR_EXCLUSION_NOMEM; - goto error; - } - - DBG("Receiving var len exclusion event list from client ..."); - exclusion->count = count; - ret = lttcomm_recv_unix_sock(*sock, exclusion->names, - count * LTTNG_SYMBOL_NAME_LEN); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - free(exclusion); - ret = LTTNG_ERR_EXCLUSION_INVAL; - goto error; - } - } - - /* Get filter expression from client. */ - if (cmd_ctx->lsm.u.enable.expression_len > 0) { - size_t expression_len = - cmd_ctx->lsm.u.enable.expression_len; - - if (expression_len > LTTNG_FILTER_MAX_LEN) { - ret = LTTNG_ERR_FILTER_INVAL; - free(exclusion); - goto error; - } - - filter_expression = zmalloc(expression_len); - if (!filter_expression) { - free(exclusion); - ret = LTTNG_ERR_FILTER_NOMEM; - goto error; - } - - /* Receive var. len. data */ - DBG("Receiving var len filter's expression from client ..."); - ret = lttcomm_recv_unix_sock(*sock, filter_expression, - expression_len); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - free(filter_expression); - free(exclusion); - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - } - - /* Handle filter and get bytecode from client. */ - if (cmd_ctx->lsm.u.enable.bytecode_len > 0) { - size_t bytecode_len = cmd_ctx->lsm.u.enable.bytecode_len; - - if (bytecode_len > LTTNG_FILTER_MAX_LEN) { - ret = LTTNG_ERR_FILTER_INVAL; - free(filter_expression); - free(exclusion); - goto error; - } - - bytecode = zmalloc(bytecode_len); - if (!bytecode) { - free(filter_expression); - free(exclusion); - ret = LTTNG_ERR_FILTER_NOMEM; - goto error; - } - - /* Receive var. len. data */ - DBG("Receiving var len filter's bytecode from client ..."); - ret = lttcomm_recv_unix_sock(*sock, bytecode, bytecode_len); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - free(filter_expression); - free(bytecode); - free(exclusion); - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - - if ((bytecode->len + sizeof(*bytecode)) != bytecode_len) { - free(filter_expression); - free(bytecode); - free(exclusion); - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - } - - ev = lttng_event_copy(ALIGNED_CONST_PTR(cmd_ctx->lsm.u.enable.event)); - if (!ev) { - DBG("Failed to copy event: %s", - cmd_ctx->lsm.u.enable.event.name); - free(filter_expression); - free(bytecode); - free(exclusion); - ret = LTTNG_ERR_NOMEM; - goto error; - } - - - if (cmd_ctx->lsm.u.enable.userspace_probe_location_len > 0) { - /* Expect a userspace probe description. */ - ret = receive_userspace_probe(cmd_ctx, *sock, sock_error, ev); - if (ret) { - free(filter_expression); - free(bytecode); - free(exclusion); - lttng_event_destroy(ev); - goto error; - } - } - - ret = cmd_enable_event(cmd_ctx->session, - ALIGNED_CONST_PTR(cmd_ctx->lsm.domain), - cmd_ctx->lsm.u.enable.channel_name, - ev, - filter_expression, bytecode, exclusion, - the_kernel_poll_pipe[1]); - lttng_event_destroy(ev); - break; - } - case LTTNG_LIST_TRACEPOINTS: - { - struct lttng_event *events; - ssize_t nb_events; - - session_lock_list(); - nb_events = cmd_list_tracepoints(cmd_ctx->lsm.domain.type, &events); - session_unlock_list(); - if (nb_events < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -nb_events; - goto error; - } - - /* - * Setup lttng message with payload size set to the event list size in - * bytes and then copy list into the llm payload. - */ - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, events, - sizeof(struct lttng_event) * nb_events); - free(events); - - if (ret < 0) { - goto setup_error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_LIST_TRACEPOINT_FIELDS: - { - struct lttng_event_field *fields; - ssize_t nb_fields; - - session_lock_list(); - nb_fields = cmd_list_tracepoint_fields(cmd_ctx->lsm.domain.type, - &fields); - session_unlock_list(); - if (nb_fields < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -nb_fields; - goto error; - } - - /* - * Setup lttng message with payload size set to the event list size in - * bytes and then copy list into the llm payload. - */ - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, fields, - sizeof(struct lttng_event_field) * nb_fields); - free(fields); - - if (ret < 0) { - goto setup_error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_LIST_SYSCALLS: - { - struct lttng_event *events; - ssize_t nb_events; - - nb_events = cmd_list_syscalls(&events); - if (nb_events < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -nb_events; - goto error; - } - - /* - * Setup lttng message with payload size set to the event list size in - * bytes and then copy list into the llm payload. - */ - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, events, - sizeof(struct lttng_event) * nb_events); - free(events); - - if (ret < 0) { - goto setup_error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_SET_CONSUMER_URI: - { - size_t nb_uri, len; - struct lttng_uri *uris; - - nb_uri = cmd_ctx->lsm.u.uri.size; - len = nb_uri * sizeof(struct lttng_uri); - - if (nb_uri == 0) { - ret = LTTNG_ERR_INVALID; - goto error; - } - - uris = zmalloc(len); - if (uris == NULL) { - ret = LTTNG_ERR_FATAL; - goto error; - } - - /* Receive variable len data */ - DBG("Receiving %zu URI(s) from client ...", nb_uri); - ret = lttcomm_recv_unix_sock(*sock, uris, len); - if (ret <= 0) { - DBG("No URIs received from client... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_SESSION_FAIL; - free(uris); - goto error; - } - - ret = cmd_set_consumer_uri(cmd_ctx->session, nb_uri, uris); - free(uris); - if (ret != LTTNG_OK) { - goto error; - } - - - break; - } - case LTTNG_START_TRACE: - { - /* - * On the first start, if we have a kernel session and we have - * enabled time or size-based rotations, we have to make sure - * the kernel tracer supports it. - */ - if (!cmd_ctx->session->has_been_started && \ - cmd_ctx->session->kernel_session && \ - (cmd_ctx->session->rotate_timer_period || \ - cmd_ctx->session->rotate_size) && \ - !check_rotate_compatible()) { - DBG("Kernel tracer version is not compatible with the rotation feature"); - ret = LTTNG_ERR_ROTATION_WRONG_VERSION; - goto error; - } - ret = cmd_start_trace(cmd_ctx->session); - break; - } - case LTTNG_STOP_TRACE: - { - ret = cmd_stop_trace(cmd_ctx->session); - break; - } - case LTTNG_DESTROY_SESSION: - { - ret = cmd_destroy_session(cmd_ctx->session, - the_notification_thread_handle, sock); - break; - } - case LTTNG_LIST_DOMAINS: - { - ssize_t nb_dom; - struct lttng_domain *domains = NULL; - - nb_dom = cmd_list_domains(cmd_ctx->session, &domains); - if (nb_dom < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -nb_dom; - goto error; - } - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, domains, - nb_dom * sizeof(struct lttng_domain)); - free(domains); - - if (ret < 0) { - goto setup_error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_LIST_CHANNELS: - { - ssize_t payload_size; - struct lttng_channel *channels = NULL; - - payload_size = cmd_list_channels(cmd_ctx->lsm.domain.type, - cmd_ctx->session, &channels); - if (payload_size < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -payload_size; - goto error; - } - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, channels, - payload_size); - free(channels); - - if (ret < 0) { - goto setup_error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_LIST_EVENTS: - { - ssize_t list_ret; - struct lttcomm_event_command_header cmd_header = {}; - size_t original_payload_size; - size_t payload_size; - - ret = setup_empty_lttng_msg(cmd_ctx); - if (ret) { - ret = LTTNG_ERR_NOMEM; - goto setup_error; - } - - original_payload_size = cmd_ctx->reply_payload.buffer.size; - - /* Extended infos are included at the end of the payload. */ - list_ret = cmd_list_events(cmd_ctx->lsm.domain.type, - cmd_ctx->session, - cmd_ctx->lsm.u.list.channel_name, - &cmd_ctx->reply_payload); - if (list_ret < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -list_ret; - goto error; - } - - payload_size = cmd_ctx->reply_payload.buffer.size - - sizeof(cmd_header) - original_payload_size; - update_lttng_msg(cmd_ctx, sizeof(cmd_header), payload_size); - - ret = LTTNG_OK; - break; - } - case LTTNG_LIST_SESSIONS: - { - unsigned int nr_sessions; - void *sessions_payload; - size_t payload_len; - - session_lock_list(); - nr_sessions = lttng_sessions_count( - LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), - LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)); - - payload_len = (sizeof(struct lttng_session) * nr_sessions) + - (sizeof(struct lttng_session_extended) * nr_sessions); - sessions_payload = zmalloc(payload_len); - - if (!sessions_payload) { - session_unlock_list(); - ret = -ENOMEM; - goto setup_error; - } - - cmd_list_lttng_sessions(sessions_payload, nr_sessions, - LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), - LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)); - session_unlock_list(); - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, sessions_payload, - payload_len); - free(sessions_payload); - - if (ret < 0) { - goto setup_error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_REGISTER_CONSUMER: - { - struct consumer_data *cdata; - - switch (cmd_ctx->lsm.domain.type) { - case LTTNG_DOMAIN_KERNEL: - cdata = &the_kconsumer_data; - break; - default: - ret = LTTNG_ERR_UND; - goto error; - } - - ret = cmd_register_consumer(cmd_ctx->session, cmd_ctx->lsm.domain.type, - cmd_ctx->lsm.u.reg.path, cdata); - break; - } - case LTTNG_DATA_PENDING: - { - int pending_ret; - uint8_t pending_ret_byte; - - pending_ret = cmd_data_pending(cmd_ctx->session); - - /* - * FIXME - * - * This function may returns 0 or 1 to indicate whether or not - * there is data pending. In case of error, it should return an - * LTTNG_ERR code. However, some code paths may still return - * a nondescript error code, which we handle by returning an - * "unknown" error. - */ - if (pending_ret == 0 || pending_ret == 1) { - /* - * ret will be set to LTTNG_OK at the end of - * this function. - */ - } else if (pending_ret < 0) { - ret = LTTNG_ERR_UNK; - goto setup_error; - } else { - ret = pending_ret; - goto setup_error; - } - - pending_ret_byte = (uint8_t) pending_ret; - - /* 1 byte to return whether or not data is pending */ - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, - &pending_ret_byte, 1); - - if (ret < 0) { - goto setup_error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_SNAPSHOT_ADD_OUTPUT: - { - uint32_t snapshot_id; - struct lttcomm_lttng_output_id reply; - - ret = cmd_snapshot_add_output(cmd_ctx->session, - ALIGNED_CONST_PTR(cmd_ctx->lsm.u.snapshot_output.output), - &snapshot_id); - if (ret != LTTNG_OK) { - goto error; - } - reply.id = snapshot_id; - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &reply, - sizeof(reply)); - if (ret < 0) { - goto setup_error; - } - - /* Copy output list into message payload */ - ret = LTTNG_OK; - break; - } - case LTTNG_SNAPSHOT_DEL_OUTPUT: - { - ret = cmd_snapshot_del_output(cmd_ctx->session, - ALIGNED_CONST_PTR(cmd_ctx->lsm.u.snapshot_output.output)); - break; - } - case LTTNG_SNAPSHOT_LIST_OUTPUT: - { - ssize_t nb_output; - struct lttng_snapshot_output *outputs = NULL; - - nb_output = cmd_snapshot_list_outputs(cmd_ctx->session, &outputs); - if (nb_output < 0) { - ret = -nb_output; - goto error; - } - - LTTNG_ASSERT((nb_output > 0 && outputs) || nb_output == 0); - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, outputs, - nb_output * sizeof(struct lttng_snapshot_output)); - free(outputs); - - if (ret < 0) { - goto setup_error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_SNAPSHOT_RECORD: - { - ret = cmd_snapshot_record(cmd_ctx->session, - ALIGNED_CONST_PTR(cmd_ctx->lsm.u.snapshot_record.output), - cmd_ctx->lsm.u.snapshot_record.wait); - break; - } - case LTTNG_CREATE_SESSION_EXT: - { - struct lttng_dynamic_buffer payload; - struct lttng_session_descriptor *return_descriptor = NULL; - - lttng_dynamic_buffer_init(&payload); - ret = cmd_create_session(cmd_ctx, *sock, &return_descriptor); - if (ret != LTTNG_OK) { - goto error; - } - - ret = lttng_session_descriptor_serialize(return_descriptor, - &payload); - if (ret) { - ERR("Failed to serialize session descriptor in reply to \"create session\" command"); - lttng_session_descriptor_destroy(return_descriptor); - ret = LTTNG_ERR_NOMEM; - goto error; - } - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, payload.data, - payload.size); - if (ret) { - lttng_session_descriptor_destroy(return_descriptor); - ret = LTTNG_ERR_NOMEM; - goto error; - } - lttng_dynamic_buffer_reset(&payload); - lttng_session_descriptor_destroy(return_descriptor); - ret = LTTNG_OK; - break; - } - case LTTNG_SAVE_SESSION: - { - ret = cmd_save_sessions(&cmd_ctx->lsm.u.save_session.attr, - &cmd_ctx->creds); - break; - } - case LTTNG_SET_SESSION_SHM_PATH: - { - ret = cmd_set_session_shm_path(cmd_ctx->session, - cmd_ctx->lsm.u.set_shm_path.shm_path); - break; - } - case LTTNG_REGENERATE_METADATA: - { - ret = cmd_regenerate_metadata(cmd_ctx->session); - break; - } - case LTTNG_REGENERATE_STATEDUMP: - { - ret = cmd_regenerate_statedump(cmd_ctx->session); - break; - } - case LTTNG_REGISTER_TRIGGER: - { - struct lttng_trigger *payload_trigger; - struct lttng_trigger *return_trigger; - size_t original_reply_payload_size; - size_t reply_payload_size; - const struct lttng_credentials cmd_creds = { - .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid), - .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid), - }; - - ret = setup_empty_lttng_msg(cmd_ctx); - if (ret) { - ret = LTTNG_ERR_NOMEM; - goto setup_error; - } - - ret = receive_lttng_trigger( - cmd_ctx, *sock, sock_error, &payload_trigger); - if (ret != LTTNG_OK) { - goto error; - } - - original_reply_payload_size = cmd_ctx->reply_payload.buffer.size; - - ret = cmd_register_trigger(&cmd_creds, payload_trigger, - cmd_ctx->lsm.u.trigger.is_trigger_anonymous, - the_notification_thread_handle, - &return_trigger); - if (ret != LTTNG_OK) { - lttng_trigger_put(payload_trigger); - goto error; - } - - ret = lttng_trigger_serialize(return_trigger, &cmd_ctx->reply_payload); - lttng_trigger_put(payload_trigger); - lttng_trigger_put(return_trigger); - if (ret) { - ERR("Failed to serialize trigger in reply to \"register trigger\" command"); - ret = LTTNG_ERR_NOMEM; - goto error; - } - - reply_payload_size = cmd_ctx->reply_payload.buffer.size - - original_reply_payload_size; - - update_lttng_msg(cmd_ctx, 0, reply_payload_size); - - ret = LTTNG_OK; - break; - } - case LTTNG_UNREGISTER_TRIGGER: - { - struct lttng_trigger *payload_trigger; - const struct lttng_credentials cmd_creds = { - .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid), - .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid), - }; - - ret = receive_lttng_trigger( - cmd_ctx, *sock, sock_error, &payload_trigger); - if (ret != LTTNG_OK) { - goto error; - } - - ret = cmd_unregister_trigger(&cmd_creds, payload_trigger, - the_notification_thread_handle); - lttng_trigger_put(payload_trigger); - break; - } - case LTTNG_ROTATE_SESSION: - { - struct lttng_rotate_session_return rotate_return; - - DBG("Client rotate session \"%s\"", cmd_ctx->session->name); - - memset(&rotate_return, 0, sizeof(rotate_return)); - if (cmd_ctx->session->kernel_session && !check_rotate_compatible()) { - DBG("Kernel tracer version is not compatible with the rotation feature"); - ret = LTTNG_ERR_ROTATION_WRONG_VERSION; - goto error; - } - - ret = cmd_rotate_session(cmd_ctx->session, &rotate_return, - false, - LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED); - if (ret < 0) { - ret = -ret; - goto error; - } - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &rotate_return, - sizeof(rotate_return)); - if (ret < 0) { - ret = -ret; - goto error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_ROTATION_GET_INFO: - { - struct lttng_rotation_get_info_return get_info_return; - - memset(&get_info_return, 0, sizeof(get_info_return)); - ret = cmd_rotate_get_info(cmd_ctx->session, &get_info_return, - cmd_ctx->lsm.u.get_rotation_info.rotation_id); - if (ret < 0) { - ret = -ret; - goto error; - } - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &get_info_return, - sizeof(get_info_return)); - if (ret < 0) { - ret = -ret; - goto error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_ROTATION_SET_SCHEDULE: - { - bool set_schedule; - enum lttng_rotation_schedule_type schedule_type; - uint64_t value; - - if (cmd_ctx->session->kernel_session && !check_rotate_compatible()) { - DBG("Kernel tracer version does not support session rotations"); - ret = LTTNG_ERR_ROTATION_WRONG_VERSION; - goto error; - } - - set_schedule = cmd_ctx->lsm.u.rotation_set_schedule.set == 1; - schedule_type = (enum lttng_rotation_schedule_type) cmd_ctx->lsm.u.rotation_set_schedule.type; - value = cmd_ctx->lsm.u.rotation_set_schedule.value; - - ret = cmd_rotation_set_schedule(cmd_ctx->session, set_schedule, - schedule_type, value, - the_notification_thread_handle); - if (ret != LTTNG_OK) { - goto error; - } - - break; - } - case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: - { - struct lttng_session_list_schedules_return schedules = { - .periodic.set = !!cmd_ctx->session->rotate_timer_period, - .periodic.value = cmd_ctx->session->rotate_timer_period, - .size.set = !!cmd_ctx->session->rotate_size, - .size.value = cmd_ctx->session->rotate_size, - }; - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &schedules, - sizeof(schedules)); - if (ret < 0) { - ret = -ret; - goto error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_CLEAR_SESSION: - { - ret = cmd_clear_session(cmd_ctx->session, sock); - break; - } - case LTTNG_LIST_TRIGGERS: - { - struct lttng_triggers *return_triggers = NULL; - size_t original_payload_size; - size_t payload_size; - - ret = setup_empty_lttng_msg(cmd_ctx); - if (ret) { - ret = LTTNG_ERR_NOMEM; - goto setup_error; - } - - original_payload_size = cmd_ctx->reply_payload.buffer.size; - - ret = cmd_list_triggers(cmd_ctx, the_notification_thread_handle, - &return_triggers); - if (ret != LTTNG_OK) { - goto error; - } - - LTTNG_ASSERT(return_triggers); - ret = lttng_triggers_serialize( - return_triggers, &cmd_ctx->reply_payload); - lttng_triggers_destroy(return_triggers); - if (ret) { - ERR("Failed to serialize triggers in reply to `list triggers` command"); - ret = LTTNG_ERR_NOMEM; - goto error; - } - - payload_size = cmd_ctx->reply_payload.buffer.size - - original_payload_size; - - update_lttng_msg(cmd_ctx, 0, payload_size); - - ret = LTTNG_OK; - break; - } - case LTTNG_EXECUTE_ERROR_QUERY: - { - struct lttng_error_query *query; - const struct lttng_credentials cmd_creds = { - .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid), - .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid), - }; - struct lttng_error_query_results *results = NULL; - size_t original_payload_size; - size_t payload_size; - - ret = setup_empty_lttng_msg(cmd_ctx); - if (ret) { - ret = LTTNG_ERR_NOMEM; - goto setup_error; - } - - original_payload_size = cmd_ctx->reply_payload.buffer.size; - - ret = receive_lttng_error_query( - cmd_ctx, *sock, sock_error, &query); - if (ret != LTTNG_OK) { - goto error; - } - - ret = cmd_execute_error_query(&cmd_creds, query, &results, - the_notification_thread_handle); - lttng_error_query_destroy(query); - if (ret != LTTNG_OK) { - goto error; - } - - LTTNG_ASSERT(results); - ret = lttng_error_query_results_serialize( - results, &cmd_ctx->reply_payload); - lttng_error_query_results_destroy(results); - if (ret) { - ERR("Failed to serialize error query result set in reply to `execute error query` command"); - ret = LTTNG_ERR_NOMEM; - goto error; - } - - payload_size = cmd_ctx->reply_payload.buffer.size - - original_payload_size; - - update_lttng_msg(cmd_ctx, 0, payload_size); - - ret = LTTNG_OK; - - break; - } - default: - ret = LTTNG_ERR_UND; - break; - } - -error: - if (cmd_ctx->reply_payload.buffer.size == 0) { - DBG("Missing llm header, creating one."); - if (setup_lttng_msg_no_cmd_header(cmd_ctx, NULL, 0) < 0) { - goto setup_error; - } - } - /* Set return code */ - ((struct lttcomm_lttng_msg *) (cmd_ctx->reply_payload.buffer.data))->ret_code = ret; -setup_error: - if (cmd_ctx->session) { - session_unlock(cmd_ctx->session); - session_put(cmd_ctx->session); - cmd_ctx->session = NULL; - } - if (need_tracing_session) { - session_unlock_list(); - } -init_setup_error: - LTTNG_ASSERT(!rcu_read_ongoing()); - return ret; -} - -static int create_client_sock(void) -{ - int ret, client_sock; - const mode_t old_umask = umask(0); - - /* Create client tool unix socket */ - client_sock = lttcomm_create_unix_sock( - the_config.client_unix_sock_path.value); - if (client_sock < 0) { - ERR("Create unix sock failed: %s", - the_config.client_unix_sock_path.value); - ret = -1; - goto end; - } - - /* Set the cloexec flag */ - ret = utils_set_fd_cloexec(client_sock); - if (ret < 0) { - ERR("Unable to set CLOEXEC flag to the client Unix socket (fd: %d). " - "Continuing but note that the consumer daemon will have a " - "reference to this socket on exec()", client_sock); - } - - /* File permission MUST be 660 */ - ret = chmod(the_config.client_unix_sock_path.value, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if (ret < 0) { - ERR("Set file permissions failed: %s", - the_config.client_unix_sock_path.value); - PERROR("chmod"); - (void) lttcomm_close_unix_sock(client_sock); - ret = -1; - goto end; - } - DBG("Created client socket (fd = %i)", client_sock); - ret = client_sock; -end: - umask(old_umask); - return ret; -} - -static void cleanup_client_thread(void *data) -{ - struct lttng_pipe *quit_pipe = data; - - lttng_pipe_destroy(quit_pipe); -} - -static void thread_init_cleanup(void *data) -{ - set_thread_status(false); -} - -/* - * This thread manage all clients request using the unix client socket for - * communication. - */ -static void *thread_manage_clients(void *data) -{ - int sock = -1, ret, i, pollfd, err = -1; - int sock_error; - uint32_t revents, nb_fd; - struct lttng_poll_event events; - const int client_sock = thread_state.client_sock; - struct lttng_pipe *quit_pipe = data; - const int thread_quit_pipe_fd = lttng_pipe_get_readfd(quit_pipe); - struct command_ctx cmd_ctx = {}; - - DBG("[thread] Manage client started"); - - lttng_payload_init(&cmd_ctx.reply_payload); - - is_root = (getuid() == 0); - - pthread_cleanup_push(thread_init_cleanup, NULL); - - rcu_register_thread(); - - health_register(the_health_sessiond, HEALTH_SESSIOND_TYPE_CMD); - - health_code_update(); - - ret = lttcomm_listen_unix_sock(client_sock); - if (ret < 0) { - goto error_listen; - } - - /* - * Pass 2 as size here for the thread quit pipe and client_sock. Nothing - * more will be added to this poll set. - */ - ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC); - if (ret < 0) { - goto error_create_poll; - } - - /* Add the application registration socket */ - ret = lttng_poll_add(&events, client_sock, LPOLLIN | LPOLLPRI); - if (ret < 0) { - goto error; - } - - /* Add thread quit pipe */ - ret = lttng_poll_add(&events, thread_quit_pipe_fd, LPOLLIN | LPOLLERR); - if (ret < 0) { - goto error; - } - - /* Set state as running. */ - set_thread_status(true); - pthread_cleanup_pop(0); - - /* This testpoint is after we signal readiness to the parent. */ - if (testpoint(sessiond_thread_manage_clients)) { - goto error; - } - - if (testpoint(sessiond_thread_manage_clients_before_loop)) { - goto error; - } - - health_code_update(); - - while (1) { - const struct cmd_completion_handler *cmd_completion_handler; - - cmd_ctx.creds = (lttng_sock_cred) { - .uid = UINT32_MAX, - .gid = UINT32_MAX, - }; - cmd_ctx.session = NULL; - lttng_payload_clear(&cmd_ctx.reply_payload); - cmd_ctx.lttng_msg_size = 0; - - DBG("Accepting client command ..."); - - /* Inifinite blocking call, waiting for transmission */ - restart: - health_poll_entry(); - ret = lttng_poll_wait(&events, -1); - health_poll_exit(); - if (ret < 0) { - /* - * Restart interrupted system call. - */ - if (errno == EINTR) { - goto restart; - } - goto error; - } - - nb_fd = ret; - - for (i = 0; i < nb_fd; i++) { - revents = LTTNG_POLL_GETEV(&events, i); - pollfd = LTTNG_POLL_GETFD(&events, i); - - health_code_update(); - - if (pollfd == thread_quit_pipe_fd) { - err = 0; - goto exit; - } else { - /* Event on the registration socket */ - if (revents & LPOLLIN) { - continue; - } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { - ERR("Client socket poll error"); - goto error; - } else { - ERR("Unexpected poll events %u for sock %d", revents, pollfd); - goto error; - } - } - } - - DBG("Wait for client response"); - - health_code_update(); - - sock = lttcomm_accept_unix_sock(client_sock); - if (sock < 0) { - goto error; - } - - /* - * Set the CLOEXEC flag. Return code is useless because either way, the - * show must go on. - */ - (void) utils_set_fd_cloexec(sock); - - /* Set socket option for credentials retrieval */ - ret = lttcomm_setsockopt_creds_unix_sock(sock); - if (ret < 0) { - goto error; - } - - health_code_update(); - - /* - * Data is received from the lttng client. The struct - * lttcomm_session_msg (lsm) contains the command and data request of - * the client. - */ - DBG("Receiving data from client ..."); - ret = lttcomm_recv_creds_unix_sock(sock, &cmd_ctx.lsm, - sizeof(struct lttcomm_session_msg), &cmd_ctx.creds); - if (ret != sizeof(struct lttcomm_session_msg)) { - DBG("Incomplete recv() from client... continuing"); - ret = close(sock); - if (ret) { - PERROR("close"); - } - sock = -1; - continue; - } - - health_code_update(); - - // TODO: Validate cmd_ctx including sanity check for - // security purpose. - - rcu_thread_online(); - /* - * This function dispatch the work to the kernel or userspace tracer - * libs and fill the lttcomm_lttng_msg data structure of all the needed - * informations for the client. The command context struct contains - * everything this function may needs. - */ - ret = process_client_msg(&cmd_ctx, &sock, &sock_error); - rcu_thread_offline(); - if (ret < 0) { - if (sock >= 0) { - ret = close(sock); - if (ret) { - PERROR("close"); - } - } - sock = -1; - /* - * TODO: Inform client somehow of the fatal error. At - * this point, ret < 0 means that a zmalloc failed - * (ENOMEM). Error detected but still accept - * command, unless a socket error has been - * detected. - */ - continue; - } - - if (ret < LTTNG_OK || ret >= LTTNG_ERR_NR) { - WARN("Command returned an invalid status code, returning unknown error: " - "command type = %s (%d), ret = %d", - lttcomm_sessiond_command_str(cmd_ctx.lsm.cmd_type), - cmd_ctx.lsm.cmd_type, ret); - ret = LTTNG_ERR_UNK; - } - - cmd_completion_handler = cmd_pop_completion_handler(); - if (cmd_completion_handler) { - enum lttng_error_code completion_code; - - completion_code = cmd_completion_handler->run( - cmd_completion_handler->data); - if (completion_code != LTTNG_OK) { - continue; - } - } - - health_code_update(); - - if (sock >= 0) { - struct lttng_payload_view view = - lttng_payload_view_from_payload( - &cmd_ctx.reply_payload, - 0, -1); - struct lttcomm_lttng_msg *llm = (typeof( - llm)) cmd_ctx.reply_payload.buffer.data; - - LTTNG_ASSERT(cmd_ctx.reply_payload.buffer.size >= sizeof(*llm)); - LTTNG_ASSERT(cmd_ctx.lttng_msg_size == cmd_ctx.reply_payload.buffer.size); - - llm->fd_count = lttng_payload_view_get_fd_handle_count(&view); - - DBG("Sending response (size: %d, retcode: %s (%d))", - cmd_ctx.lttng_msg_size, - lttng_strerror(-llm->ret_code), - llm->ret_code); - ret = send_unix_sock(sock, &view); - if (ret < 0) { - ERR("Failed to send data back to client"); - } - - /* End of transmission */ - ret = close(sock); - if (ret) { - PERROR("close"); - } - } - sock = -1; - - health_code_update(); - } - -exit: -error: - if (sock >= 0) { - ret = close(sock); - if (ret) { - PERROR("close"); - } - } - - lttng_poll_clean(&events); - -error_listen: -error_create_poll: - unlink(the_config.client_unix_sock_path.value); - ret = close(client_sock); - if (ret) { - PERROR("close"); - } - - if (err) { - health_error(); - ERR("Health error occurred in %s", __func__); - } - - health_unregister(the_health_sessiond); - - DBG("Client thread dying"); - lttng_payload_reset(&cmd_ctx.reply_payload); - rcu_unregister_thread(); - return NULL; -} - -static -bool shutdown_client_thread(void *thread_data) -{ - struct lttng_pipe *client_quit_pipe = thread_data; - const int write_fd = lttng_pipe_get_writefd(client_quit_pipe); - - return notify_thread_pipe(write_fd) == 1; -} - -struct lttng_thread *launch_client_thread(void) -{ - bool thread_running; - struct lttng_pipe *client_quit_pipe; - struct lttng_thread *thread = NULL; - int client_sock_fd = -1; - - sem_init(&thread_state.ready, 0, 0); - client_quit_pipe = lttng_pipe_open(FD_CLOEXEC); - if (!client_quit_pipe) { - goto error; - } - - client_sock_fd = create_client_sock(); - if (client_sock_fd < 0) { - goto error; - } - - thread_state.client_sock = client_sock_fd; - thread = lttng_thread_create("Client management", - thread_manage_clients, - shutdown_client_thread, - cleanup_client_thread, - client_quit_pipe); - if (!thread) { - goto error; - } - /* The client thread now owns the client sock fd and the quit pipe. */ - client_sock_fd = -1; - client_quit_pipe = NULL; - - /* - * This thread is part of the threads that need to be fully - * initialized before the session daemon is marked as "ready". - */ - thread_running = wait_thread_status(); - if (!thread_running) { - goto error; - } - return thread; -error: - if (client_sock_fd >= 0) { - if (close(client_sock_fd)) { - PERROR("Failed to close client socket"); - } - } - lttng_thread_put(thread); - cleanup_client_thread(client_quit_pipe); - return NULL; -}