X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fcmd.c;h=3b776c57634fcfa5f05688a2c7b2c8233fb505b7;hp=d8d17b59cba2b07956ff7e08bf13c685dfca37da;hb=cc3b9644f017a91d347d7a414387292e3175635e;hpb=64eafdf60552bbd7e22fb1c8fc8fc2b42a3cf68b diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index d8d17b59c..3b776c576 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -6,61 +6,69 @@ * */ + #define _LGPL_SOURCE #include #include +#include +#include #include #include -#include -#include -#include +#include #include -#include -#include -#include #include -#include +#include #include -#include -#include +#include #include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include #include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include #include +#include +#include +#include #include -#include +#include +#include +#include "agent-thread.h" +#include "agent.h" +#include "buffer-registry.h" #include "channel.h" +#include "cmd.h" #include "consumer.h" +#include "event-notifier-error-accounting.h" #include "event.h" #include "health-sessiond.h" -#include "kernel.h" #include "kernel-consumer.h" +#include "kernel.h" #include "lttng-sessiond.h" -#include "utils.h" #include "lttng-syscall.h" -#include "agent.h" -#include "buffer-registry.h" -#include "notification-thread.h" #include "notification-thread-commands.h" +#include "notification-thread.h" #include "rotate.h" #include "rotation-thread.h" +#include "session.h" #include "timer.h" -#include "agent-thread.h" #include "tracker.h" - -#include "cmd.h" +#include "utils.h" /* Sleep for 100ms between each check for the shm path's deletion. */ #define SESSION_DESTROY_SHM_PATH_CHECK_DELAY_US 100000 @@ -110,7 +118,7 @@ static int cmd_enable_event_internal(struct ltt_session *session, const struct lttng_domain *domain, char *channel_name, struct lttng_event *event, char *filter_expression, - struct lttng_filter_bytecode *filter, + struct lttng_bytecode *filter, struct lttng_event_exclusion *exclusion, int wpipe); @@ -354,7 +362,7 @@ static ssize_t list_lttng_channels(enum lttng_domain_type domain, * Map enum lttng_ust_output to enum lttng_event_output. */ switch (uchan->attr.output) { - case LTTNG_UST_MMAP: + case LTTNG_UST_ABI_MMAP: channels[i].attr.output = LTTNG_EVENT_MMAP; break; default: @@ -483,13 +491,19 @@ static int list_lttng_agent_events(struct agent *agt, cds_lfht_for_each_entry ( agt->events->ht, &iter.iter, agent_event, node.node) { struct lttng_event event = { - .enabled = agent_event->enabled, + .enabled = AGENT_EVENT_IS_ENABLED(agent_event), .loglevel = agent_event->loglevel_value, .loglevel_type = agent_event->loglevel_type, }; - strncpy(event.name, agent_event->name, sizeof(event.name)); - event.name[sizeof(event.name) - 1] = '\0'; + ret = lttng_strncpy(event.name, agent_event->name, sizeof(event.name)); + if (ret) { + /* Internal error, invalid name. */ + ERR("Invalid event name while listing agent events: '%s' exceeds the maximal allowed length of %zu bytes", + agent_event->name, sizeof(event.name)); + ret = -LTTNG_ERR_UNK; + goto end; + } ret = lttng_dynamic_buffer_append( &payload->buffer, &event, sizeof(event)); @@ -556,32 +570,38 @@ static int list_lttng_ust_global_events(char *channel_name, continue; } - strncpy(event.name, uevent->attr.name, sizeof(event.name)); - event.name[sizeof(event.name) - 1] = '\0'; + ret = lttng_strncpy(event.name, uevent->attr.name, sizeof(event.name)); + if (ret) { + /* Internal error, invalid name. */ + ERR("Invalid event name while listing user space tracer events: '%s' exceeds the maximal allowed length of %zu bytes", + uevent->attr.name, sizeof(event.name)); + ret = -LTTNG_ERR_UNK; + goto end; + } event.enabled = uevent->enabled; switch (uevent->attr.instrumentation) { - case LTTNG_UST_TRACEPOINT: + case LTTNG_UST_ABI_TRACEPOINT: event.type = LTTNG_EVENT_TRACEPOINT; break; - case LTTNG_UST_PROBE: + case LTTNG_UST_ABI_PROBE: event.type = LTTNG_EVENT_PROBE; break; - case LTTNG_UST_FUNCTION: + case LTTNG_UST_ABI_FUNCTION: event.type = LTTNG_EVENT_FUNCTION; break; } event.loglevel = uevent->attr.loglevel; switch (uevent->attr.loglevel_type) { - case LTTNG_UST_LOGLEVEL_ALL: + case LTTNG_UST_ABI_LOGLEVEL_ALL: event.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; break; - case LTTNG_UST_LOGLEVEL_RANGE: + case LTTNG_UST_ABI_LOGLEVEL_RANGE: event.loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE; break; - case LTTNG_UST_LOGLEVEL_SINGLE: + case LTTNG_UST_ABI_LOGLEVEL_SINGLE: event.loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE; break; } @@ -647,40 +667,48 @@ static int list_lttng_kernel_events(char *channel_name, cds_list_for_each_entry(kevent, &kchan->events_list.head , list) { struct lttng_event event = {}; - strncpy(event.name, kevent->event->name, sizeof(event.name)); - event.name[sizeof(event.name) - 1] = '\0'; + ret = lttng_strncpy(event.name, kevent->event->name, sizeof(event.name)); + if (ret) { + /* Internal error, invalid name. */ + ERR("Invalid event name while listing kernel events: '%s' exceeds the maximal allowed length of %zu bytes", + kevent->event->name, + sizeof(event.name)); + ret = -LTTNG_ERR_UNK; + goto end; + } + event.enabled = kevent->enabled; event.filter = (unsigned char) !!kevent->filter_expression; switch (kevent->event->instrumentation) { - case LTTNG_KERNEL_TRACEPOINT: + case LTTNG_KERNEL_ABI_TRACEPOINT: event.type = LTTNG_EVENT_TRACEPOINT; break; - case LTTNG_KERNEL_KRETPROBE: + case LTTNG_KERNEL_ABI_KRETPROBE: event.type = LTTNG_EVENT_FUNCTION; memcpy(&event.attr.probe, &kevent->event->u.kprobe, - sizeof(struct lttng_kernel_kprobe)); + sizeof(struct lttng_kernel_abi_kprobe)); break; - case LTTNG_KERNEL_KPROBE: + case LTTNG_KERNEL_ABI_KPROBE: event.type = LTTNG_EVENT_PROBE; memcpy(&event.attr.probe, &kevent->event->u.kprobe, - sizeof(struct lttng_kernel_kprobe)); + sizeof(struct lttng_kernel_abi_kprobe)); break; - case LTTNG_KERNEL_UPROBE: + case LTTNG_KERNEL_ABI_UPROBE: event.type = LTTNG_EVENT_USERSPACE_PROBE; break; - case LTTNG_KERNEL_FUNCTION: + case LTTNG_KERNEL_ABI_FUNCTION: event.type = LTTNG_EVENT_FUNCTION; memcpy(&event.attr.ftrace, &kevent->event->u.ftrace, - sizeof(struct lttng_kernel_function)); + sizeof(struct lttng_kernel_abi_function)); break; - case LTTNG_KERNEL_NOOP: + case LTTNG_KERNEL_ABI_NOOP: event.type = LTTNG_EVENT_NOOP; break; - case LTTNG_KERNEL_SYSCALL: + case LTTNG_KERNEL_ABI_SYSCALL: event.type = LTTNG_EVENT_SYSCALL; break; - case LTTNG_KERNEL_ALL: + case LTTNG_KERNEL_ABI_ALL: /* fall-through. */ default: assert(0); @@ -2058,7 +2086,7 @@ static int _cmd_enable_event(struct ltt_session *session, const struct lttng_domain *domain, char *channel_name, struct lttng_event *event, char *filter_expression, - struct lttng_filter_bytecode *filter, + struct lttng_bytecode *filter, struct lttng_event_exclusion *exclusion, int wpipe, bool internal_event) { @@ -2141,7 +2169,7 @@ static int _cmd_enable_event(struct ltt_session *session, case LTTNG_EVENT_ALL: { char *filter_expression_a = NULL; - struct lttng_filter_bytecode *filter_a = NULL; + struct lttng_bytecode *filter_a = NULL; /* * We need to duplicate filter_expression and filter, @@ -2376,11 +2404,11 @@ static int _cmd_enable_event(struct ltt_session *session, { char *filter_expression_copy = NULL; - struct lttng_filter_bytecode *filter_copy = NULL; + struct lttng_bytecode *filter_copy = NULL; if (filter) { const size_t filter_size = sizeof( - struct lttng_filter_bytecode) + struct lttng_bytecode) + filter->len; filter_copy = zmalloc(filter_size); @@ -2456,7 +2484,7 @@ int cmd_enable_event(struct ltt_session *session, const struct lttng_domain *domain, char *channel_name, struct lttng_event *event, char *filter_expression, - struct lttng_filter_bytecode *filter, + struct lttng_bytecode *filter, struct lttng_event_exclusion *exclusion, int wpipe) { @@ -2473,7 +2501,7 @@ static int cmd_enable_event_internal(struct ltt_session *session, const struct lttng_domain *domain, char *channel_name, struct lttng_event *event, char *filter_expression, - struct lttng_filter_bytecode *filter, + struct lttng_bytecode *filter, struct lttng_event_exclusion *exclusion, int wpipe) { @@ -3107,10 +3135,22 @@ enum lttng_error_code cmd_create_session(struct command_ctx *cmd_ctx, int sock, &payload, 0, cmd_ctx->lsm.u.create_session.home_dir_size); + if (cmd_ctx->lsm.u.create_session.home_dir_size > 0 && + !lttng_buffer_view_is_valid(&home_dir_view)) { + ERR("Invalid payload in \"create session\" command: buffer too short to contain home directory"); + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + goto error; + } + session_descriptor_view = lttng_buffer_view_from_dynamic_buffer( &payload, cmd_ctx->lsm.u.create_session.home_dir_size, cmd_ctx->lsm.u.create_session.session_descriptor_size); + if (!lttng_buffer_view_is_valid(&session_descriptor_view)) { + ERR("Invalid payload in \"create session\" command: buffer too short to contain session descriptor"); + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + goto error; + } ret = lttng_session_descriptor_create_from_buffer( &session_descriptor_view, &session_descriptor); @@ -3201,6 +3241,7 @@ void cmd_destroy_session_reply(const struct ltt_session *session, payload_size_before_location = payload.size; comm_ret = lttng_trace_archive_location_serialize(location, &payload); + lttng_trace_archive_location_put(location); if (comm_ret < 0) { ERR("Failed to serialize the location of the trace archive produced during the destruction of session \"%s\"", session->name); @@ -4166,7 +4207,7 @@ end: * then regenerate the metadata. Live and per-pid sessions are not * supported and return an error. * - * Return 0 on success or else a LTTNG_ERR code. + * Return LTTNG_OK on success or else a LTTNG_ERR code. */ int cmd_regenerate_metadata(struct ltt_session *session) { @@ -4207,7 +4248,7 @@ end: * * Ask the tracer to regenerate a new statedump. * - * Return 0 on success or else a LTTNG_ERR code. + * Return LTTNG_OK on success or else a LTTNG_ERR code. */ int cmd_regenerate_statedump(struct ltt_session *session) { @@ -4256,169 +4297,510 @@ end: return ret; } -int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock, - struct notification_thread_handle *notification_thread) +static +enum lttng_error_code synchronize_tracer_notifier_register( + struct notification_thread_handle *notification_thread, + struct lttng_trigger *trigger, const struct lttng_credentials *cmd_creds) { - int ret; - size_t trigger_len; - ssize_t sock_recv_len; - struct lttng_trigger *trigger = NULL; - struct lttng_payload trigger_payload; - struct lttng_credentials cmd_creds = { - .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid), - .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid), - }; + enum lttng_error_code ret_code; + const struct lttng_condition *condition = + lttng_trigger_get_const_condition(trigger); + const char *trigger_name; + uid_t trigger_owner; + enum lttng_trigger_status trigger_status; + const enum lttng_domain_type trigger_domain = + lttng_trigger_get_underlying_domain_type_restriction( + trigger); + + trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_owner); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + assert(condition); + assert(lttng_condition_get_type(condition) == + LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES); + + trigger_status = lttng_trigger_get_name(trigger, &trigger_name); + trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? + trigger_name : "(anonymous)"; - 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 = LTTNG_ERR_NOMEM; + session_lock_list(); + switch (trigger_domain) { + case LTTNG_DOMAIN_KERNEL: + { + ret_code = kernel_register_event_notifier(trigger, cmd_creds); + if (ret_code != LTTNG_OK) { + enum lttng_error_code notif_thread_unregister_ret; + + notif_thread_unregister_ret = + notification_thread_command_unregister_trigger( + notification_thread, trigger); + + if (notif_thread_unregister_ret != LTTNG_OK) { + /* Return the original error code. */ + ERR("Failed to unregister trigger from notification thread during error recovery: trigger name = '%s', trigger owner uid = %d, error code = %d", + trigger_name, + (int) trigger_owner, + ret_code); + } + } + break; + } + case LTTNG_DOMAIN_UST: + ust_app_global_update_all_event_notifier_rules(); + break; + case LTTNG_DOMAIN_JUL: + case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_PYTHON: + { + /* Agent domains. */ + struct agent *agt = agent_find_by_event_notifier_domain( + trigger_domain); + + if (!agt) { + agt = agent_create(trigger_domain); + if (!agt) { + ret_code = LTTNG_ERR_NOMEM; + goto end_unlock_session_list; + } + + agent_add(agt, the_trigger_agents_ht_by_domain); + } + + ret_code = trigger_agent_enable(trigger, agt); + if (ret_code != LTTNG_OK) { + goto end_unlock_session_list; + } + + break; + } + case LTTNG_DOMAIN_NONE: + default: + abort(); + } + + ret_code = LTTNG_OK; +end_unlock_session_list: + session_unlock_list(); + return ret_code; +} + +enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_creds, + struct lttng_trigger *trigger, + bool is_trigger_anonymous, + struct notification_thread_handle *notification_thread, + struct lttng_trigger **return_trigger) +{ + enum lttng_error_code ret_code; + const char *trigger_name; + uid_t trigger_owner; + enum lttng_trigger_status trigger_status; + + trigger_status = lttng_trigger_get_name(trigger, &trigger_name); + trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? + trigger_name : "(anonymous)"; + + trigger_status = lttng_trigger_get_owner_uid( + trigger, &trigger_owner); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + DBG("Running register trigger command: trigger name = '%s', trigger owner uid = %d, command creds uid = %d", + trigger_name, (int) trigger_owner, + (int) lttng_credentials_get_uid(cmd_creds)); + + /* + * Validate the trigger credentials against the command credentials. + * Only the root user can register a trigger with non-matching + * credentials. + */ + if (!lttng_credentials_is_equal_uid( + lttng_trigger_get_credentials(trigger), + cmd_creds)) { + if (lttng_credentials_get_uid(cmd_creds) != 0) { + ERR("Trigger credentials do not match the command credentials: trigger name = '%s', trigger owner uid = %d, command creds uid = %d", + trigger_name, (int) trigger_owner, + (int) lttng_credentials_get_uid(cmd_creds)); + ret_code = LTTNG_ERR_INVALID_TRIGGER; + goto end; + } + } + + /* + * The bytecode generation also serves as a validation step for the + * bytecode expressions. + */ + ret_code = lttng_trigger_generate_bytecode(trigger, cmd_creds); + if (ret_code != LTTNG_OK) { + ERR("Failed to generate bytecode of trigger: trigger name = '%s', trigger owner uid = %d, error code = %d", + trigger_name, (int) trigger_owner, ret_code); 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 \"register trigger\" command payload"); - /* TODO: should this be a new error enum ? */ - ret = LTTNG_ERR_INVALID_TRIGGER; + /* + * A reference to the trigger is acquired by the notification thread. + * It is safe to return the same trigger to the caller since it the + * other user holds a reference. + * + * The trigger is modified during the execution of the + * "register trigger" command. However, by the time the command returns, + * it is safe to use without any locking as its properties are + * immutable. + */ + ret_code = notification_thread_command_register_trigger( + notification_thread, trigger, is_trigger_anonymous); + if (ret_code != LTTNG_OK) { + DBG("Failed to register trigger to notification thread: trigger name = '%s', trigger owner uid = %d, error code = %d", + trigger_name, (int) trigger_owner, ret_code); goto end; } - /* Receive fds, if any. */ - if (cmd_ctx->lsm.fd_count > 0) { - ret = lttcomm_recv_payload_fds_unix_sock( - sock, cmd_ctx->lsm.fd_count, &trigger_payload); - if (ret > 0 && ret != cmd_ctx->lsm.fd_count * sizeof(int)) { - ret = LTTNG_ERR_INVALID_PROTOCOL; - goto end; - } else if (ret <= 0) { - ret = LTTNG_ERR_FATAL; + trigger_status = lttng_trigger_get_name(trigger, &trigger_name); + trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? + trigger_name : "(anonymous)"; + + /* + * Synchronize tracers if the trigger adds an event notifier. + */ + if (lttng_trigger_needs_tracer_notifier(trigger)) { + ret_code = synchronize_tracer_notifier_register(notification_thread, + trigger, cmd_creds); + if (ret_code != LTTNG_OK) { + ERR("Error registering tracer notifier: %s", + lttng_strerror(-ret_code)); goto end; } } - /* Deserialize trigger. */ + /* + * Return an updated trigger to the client. + * + * Since a modified version of the same trigger is returned, acquire a + * reference to the trigger so the caller doesn't have to care if those + * are distinct instances or not. + */ + if (ret_code == LTTNG_OK) { + lttng_trigger_get(trigger); + *return_trigger = trigger; + /* Ownership of trigger was transferred to caller. */ + trigger = NULL; + } +end: + return ret_code; +} + +static +enum lttng_error_code synchronize_tracer_notifier_unregister( + const struct lttng_trigger *trigger) +{ + enum lttng_error_code ret_code; + const struct lttng_condition *condition = + lttng_trigger_get_const_condition(trigger); + const enum lttng_domain_type trigger_domain = + lttng_trigger_get_underlying_domain_type_restriction( + trigger); + + assert(condition); + assert(lttng_condition_get_type(condition) == + LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES); + + session_lock_list(); + switch (trigger_domain) { + case LTTNG_DOMAIN_KERNEL: + ret_code = kernel_unregister_event_notifier(trigger); + if (ret_code != LTTNG_OK) { + goto end_unlock_session_list; + } + + break; + case LTTNG_DOMAIN_UST: + ust_app_global_update_all_event_notifier_rules(); + break; + case LTTNG_DOMAIN_JUL: + case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_PYTHON: { - 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 payload received in \"register trigger\" command"); - ret = LTTNG_ERR_INVALID_TRIGGER; - goto end; + /* Agent domains. */ + struct agent *agt = agent_find_by_event_notifier_domain( + trigger_domain); + + /* + * This trigger was never registered in the first place. Calling + * this function under those circumstances is an internal error. + */ + assert(agt); + ret_code = trigger_agent_disable(trigger, agt); + if (ret_code != LTTNG_OK) { + goto end_unlock_session_list; } + + break; } + case LTTNG_DOMAIN_NONE: + default: + abort(); + } + + ret_code = LTTNG_OK; + +end_unlock_session_list: + session_unlock_list(); + return ret_code; +} +enum lttng_error_code cmd_unregister_trigger(const struct lttng_credentials *cmd_creds, + const struct lttng_trigger *trigger, + struct notification_thread_handle *notification_thread) +{ + enum lttng_error_code ret_code; + const char *trigger_name; + uid_t trigger_owner; + enum lttng_trigger_status trigger_status; + struct lttng_trigger *sessiond_trigger = NULL; + + trigger_status = lttng_trigger_get_name(trigger, &trigger_name); + trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? trigger_name : "(anonymous)"; + trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_owner); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + DBG("Running unregister trigger command: trigger name = '%s', trigger owner uid = %d, command creds uid = %d", + trigger_name, (int) trigger_owner, + (int) lttng_credentials_get_uid(cmd_creds)); /* * Validate the trigger credentials against the command credentials. - * Only the root user can register a trigger with non-matching + * Only the root user can unregister a trigger with non-matching * credentials. */ if (!lttng_credentials_is_equal_uid( lttng_trigger_get_credentials(trigger), - &cmd_creds)) { - if (lttng_credentials_get_uid(&cmd_creds) != 0) { - ERR("Trigger credentials do not match the command credentials"); - ret = LTTNG_ERR_INVALID_TRIGGER; + cmd_creds)) { + if (lttng_credentials_get_uid(cmd_creds) != 0) { + ERR("Trigger credentials do not match the command credentials: trigger name = '%s', trigger owner uid = %d, command creds uid = %d", + trigger_name, (int) trigger_owner, + (int) lttng_credentials_get_uid(cmd_creds)); + ret_code = LTTNG_ERR_INVALID_TRIGGER; + goto end; + } + } + + /* Fetch the sessiond side trigger object. */ + ret_code = notification_thread_command_get_trigger( + notification_thread, trigger, &sessiond_trigger); + if (ret_code != LTTNG_OK) { + DBG("Failed to get trigger from notification thread during unregister: trigger name = '%s', trigger owner uid = %d, error code = %d", + trigger_name, (int) trigger_owner, ret_code); + goto end; + } + + assert(sessiond_trigger); + + /* + * From this point on, no matter what, consider the trigger + * unregistered. + * + * We set the unregistered state of the sessiond side trigger object in + * the client thread since we want to minimize the possibility of the + * notification thread being stalled due to a long execution of an + * action that required the trigger lock. + */ + lttng_trigger_set_as_unregistered(sessiond_trigger); + + ret_code = notification_thread_command_unregister_trigger(notification_thread, + trigger); + if (ret_code != LTTNG_OK) { + DBG("Failed to unregister trigger from notification thread: trigger name = '%s', trigger owner uid = %d, error code = %d", + trigger_name, (int) trigger_owner, ret_code); + goto end; + } + + /* + * Synchronize tracers if the trigger removes an event notifier. + * Do this even if the trigger unregistration failed to at least stop + * the tracers from producing notifications associated with this + * event notifier. + */ + if (lttng_trigger_needs_tracer_notifier(trigger)) { + ret_code = synchronize_tracer_notifier_unregister(trigger); + if (ret_code != LTTNG_OK) { + ERR("Error unregistering trigger to tracer."); goto end; } + } - /* Inform the notification thread */ - ret = notification_thread_command_register_trigger(notification_thread, - trigger); - /* Ownership of trigger was transferred. */ - trigger = NULL; end: - lttng_trigger_destroy(trigger); - lttng_payload_reset(&trigger_payload); - return ret; + lttng_trigger_put(sessiond_trigger); + return ret_code; } -int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock, - struct notification_thread_handle *notification_thread) +enum lttng_error_code cmd_list_triggers(struct command_ctx *cmd_ctx, + struct notification_thread_handle *notification_thread, + struct lttng_triggers **return_triggers) { int ret; - size_t trigger_len; - ssize_t sock_recv_len; - struct lttng_trigger *trigger = NULL; - struct lttng_payload trigger_payload; - struct lttng_credentials cmd_creds = { - .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid), - .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid), - }; + enum lttng_error_code ret_code; + struct lttng_triggers *triggers = NULL; + + /* Get the set of triggers from the notification thread. */ + ret_code = notification_thread_command_list_triggers( + notification_thread, cmd_ctx->creds.uid, &triggers); + if (ret_code != LTTNG_OK) { + goto end; + } - 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); + ret = lttng_triggers_remove_hidden_triggers(triggers); if (ret) { - ret = LTTNG_ERR_NOMEM; + ret_code = LTTNG_ERR_UNK; 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 \"unregister trigger\" command payload"); - /* TODO: should this be a new error enum ? */ - ret = LTTNG_ERR_INVALID_TRIGGER; + *return_triggers = triggers; + triggers = NULL; + ret_code = LTTNG_OK; +end: + lttng_triggers_destroy(triggers); + return ret_code; +} + +enum lttng_error_code cmd_execute_error_query(const struct lttng_credentials *cmd_creds, + const struct lttng_error_query *query, + struct lttng_error_query_results **_results, + struct notification_thread_handle *notification_thread) +{ + enum lttng_error_code ret_code; + const struct lttng_trigger *query_target_trigger; + const struct lttng_action *query_target_action = NULL; + struct lttng_trigger *matching_trigger = NULL; + const char *trigger_name; + uid_t trigger_owner; + enum lttng_trigger_status trigger_status; + struct lttng_error_query_results *results = NULL; + + switch (lttng_error_query_get_target_type(query)) { + case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER: + query_target_trigger = lttng_error_query_trigger_borrow_target(query); + break; + case LTTNG_ERROR_QUERY_TARGET_TYPE_CONDITION: + query_target_trigger = + lttng_error_query_condition_borrow_target(query); + break; + case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION: + query_target_trigger = lttng_error_query_action_borrow_trigger_target( + query); + break; + default: + abort(); + } + + assert(query_target_trigger); + + ret_code = notification_thread_command_get_trigger(notification_thread, + query_target_trigger, &matching_trigger); + if (ret_code != LTTNG_OK) { goto end; } - /* Receive fds, if any. */ - if (cmd_ctx->lsm.fd_count > 0) { - ret = lttcomm_recv_payload_fds_unix_sock( - sock, cmd_ctx->lsm.fd_count, &trigger_payload); - if (ret > 0 && ret != cmd_ctx->lsm.fd_count * sizeof(int)) { - ret = LTTNG_ERR_INVALID_PROTOCOL; - goto end; - } else if (ret <= 0) { - ret = LTTNG_ERR_FATAL; - goto end; - } + /* No longer needed. */ + query_target_trigger = NULL; + + if (lttng_error_query_get_target_type(query) == + LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION) { + /* Get the sessiond-side version of the target action. */ + query_target_action = + lttng_error_query_action_borrow_action_target( + query, matching_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 payload received in \"unregister trigger\" command"); - ret = LTTNG_ERR_INVALID_TRIGGER; - goto end; - } + trigger_status = lttng_trigger_get_name(matching_trigger, &trigger_name); + trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? + trigger_name : "(anonymous)"; + trigger_status = lttng_trigger_get_owner_uid(matching_trigger, + &trigger_owner); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + results = lttng_error_query_results_create(); + if (!results) { + ret_code = LTTNG_ERR_NOMEM; + goto end; } + DBG("Running \"execute error query\" command: trigger name = '%s', trigger owner uid = %d, command creds uid = %d", + trigger_name, (int) trigger_owner, + (int) lttng_credentials_get_uid(cmd_creds)); + /* * Validate the trigger credentials against the command credentials. - * Only the root user can unregister a trigger with non-matching + * Only the root user can target a trigger with non-matching * credentials. */ if (!lttng_credentials_is_equal_uid( - lttng_trigger_get_credentials(trigger), - &cmd_creds)) { - if (lttng_credentials_get_uid(&cmd_creds) != 0) { - ERR("Trigger credentials do not match the command credentials"); - ret = LTTNG_ERR_INVALID_TRIGGER; + lttng_trigger_get_credentials(matching_trigger), + cmd_creds)) { + if (lttng_credentials_get_uid(cmd_creds) != 0) { + ERR("Trigger credentials do not match the command credentials: trigger name = '%s', trigger owner uid = %d, command creds uid = %d", + trigger_name, (int) trigger_owner, + (int) lttng_credentials_get_uid(cmd_creds)); + ret_code = LTTNG_ERR_INVALID_TRIGGER; + goto end; + } + } + + switch (lttng_error_query_get_target_type(query)) { + case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER: + trigger_status = lttng_trigger_add_error_results( + matching_trigger, results); + + switch (trigger_status) { + case LTTNG_TRIGGER_STATUS_OK: + break; + default: + ret_code = LTTNG_ERR_UNK; + goto end; + } + + break; + case LTTNG_ERROR_QUERY_TARGET_TYPE_CONDITION: + { + trigger_status = lttng_trigger_condition_add_error_results( + matching_trigger, results); + + switch (trigger_status) { + case LTTNG_TRIGGER_STATUS_OK: + break; + default: + ret_code = LTTNG_ERR_UNK; + goto end; + } + + break; + } + case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION: + { + const enum lttng_action_status action_status = + lttng_action_add_error_query_results( + query_target_action, results); + + switch (action_status) { + case LTTNG_ACTION_STATUS_OK: + break; + default: + ret_code = LTTNG_ERR_UNK; goto end; } + + break; + } + default: + abort(); + break; } - ret = notification_thread_command_unregister_trigger(notification_thread, - trigger); + *_results = results; + results = NULL; + ret_code = LTTNG_OK; end: - lttng_trigger_destroy(trigger); - lttng_payload_reset(&trigger_payload); - return ret; + lttng_trigger_put(matching_trigger); + lttng_error_query_results_destroy(results); + return ret_code; } /* @@ -4671,6 +5053,11 @@ enum lttng_error_code snapshot_record(struct ltt_session *session, consumer_copy_output(snapshot_output->consumer); strcpy(snapshot_kernel_consumer_output->chunk_path, snapshot_chunk_name); + + /* Copy the original domain subdir. */ + strcpy(snapshot_kernel_consumer_output->domain_subdir, + original_kernel_consumer_output->domain_subdir); + ret = consumer_copy_sockets(snapshot_kernel_consumer_output, original_kernel_consumer_output); if (ret < 0) { @@ -4693,6 +5080,11 @@ enum lttng_error_code snapshot_record(struct ltt_session *session, consumer_copy_output(snapshot_output->consumer); strcpy(snapshot_ust_consumer_output->chunk_path, snapshot_chunk_name); + + /* Copy the original domain subdir. */ + strcpy(snapshot_ust_consumer_output->domain_subdir, + original_ust_consumer_output->domain_subdir); + ret = consumer_copy_sockets(snapshot_ust_consumer_output, original_ust_consumer_output); if (ret < 0) { @@ -4942,7 +5334,7 @@ int cmd_set_session_shm_path(struct ltt_session *session, sizeof(session->shm_path)); session->shm_path[sizeof(session->shm_path) - 1] = '\0'; - return 0; + return LTTNG_OK; } /* @@ -5115,8 +5507,8 @@ int cmd_rotate_session(struct ltt_session *session, chunk_being_archived = NULL; if (!quiet_rotation) { ret = notification_thread_command_session_rotation_ongoing( - notification_thread_handle, - session->name, session->uid, session->gid, + the_notification_thread_handle, session->name, + session->uid, session->gid, ongoing_rotation_chunk_id); if (ret != LTTNG_OK) { ERR("Failed to notify notification thread that a session rotation is ongoing for session %s", @@ -5295,7 +5687,7 @@ end: * 'activate' to false means deactivate the rotation schedule and validate that * 'new_value' has the same value as the currently active value. * - * Return 0 on success or else a positive LTTNG_ERR code. + * Return LTTNG_OK on success or else a positive LTTNG_ERR code. */ int cmd_rotation_set_schedule(struct ltt_session *session, bool activate, enum lttng_rotation_schedule_type schedule_type,