X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fcmd.c;h=2c0fa462d38fe63a728679b0dc3072ae6e88502a;hp=83ad957fcdb08912e3dd045940609d01c5e4efda;hb=8cc65d5cbccb6e4ba91c4de0efc3e974a6ca61b5;hpb=fc4b93fa8aa36b19caad0f8dc4a6a3237fcc36bf diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 83ad957fc..2c0fa462d 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -6,66 +6,68 @@ * */ + #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 #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 @@ -130,8 +132,8 @@ static int build_network_session_path(char *dst, size_t size, struct lttng_uri *kuri = NULL, *uuri = NULL, *uri = NULL; char tmp_uurl[PATH_MAX], tmp_urls[PATH_MAX]; - assert(session); - assert(dst); + LTTNG_ASSERT(session); + LTTNG_ASSERT(dst); memset(tmp_urls, 0, sizeof(tmp_urls)); memset(tmp_uurl, 0, sizeof(tmp_uurl)); @@ -249,8 +251,8 @@ static int get_ust_runtime_stats(struct ltt_session *session, } usess = session->ust_session; - assert(discarded_events); - assert(lost_packets); + LTTNG_ASSERT(discarded_events); + LTTNG_ASSERT(lost_packets); if (!usess || !session->has_been_started) { *discarded_events = 0; @@ -279,7 +281,7 @@ static int get_ust_runtime_stats(struct ltt_session *session, *lost_packets += uchan->per_pid_closed_app_lost; } else { ERR("Unsupported buffer type"); - assert(0); + abort(); ret = -1; goto end; } @@ -367,7 +369,7 @@ static ssize_t list_lttng_channels(enum lttng_domain_type domain, * LTTNG_UST_MMAP is the only supported UST * output mode. */ - assert(0); + abort(); break; } @@ -480,7 +482,7 @@ static int list_lttng_agent_events(struct agent *agt, const struct agent_event *agent_event; struct lttng_ht_iter iter; - assert(agt); + LTTNG_ASSERT(agt); DBG3("Listing agent events"); @@ -678,37 +680,37 @@ static int list_lttng_kernel_events(char *channel_name, 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); + abort(); break; } @@ -750,7 +752,7 @@ static enum lttng_error_code add_uri_to_consumer( int ret; enum lttng_error_code ret_code = LTTNG_OK; - assert(uri); + LTTNG_ASSERT(uri); if (consumer == NULL) { DBG("No consumer detected. Don't add URI. Stopping."); @@ -850,7 +852,7 @@ static int init_kernel_tracing(struct ltt_kernel_session *session) struct lttng_ht_iter iter; struct consumer_socket *socket; - assert(session); + LTTNG_ASSERT(session); rcu_read_lock(); @@ -984,7 +986,7 @@ static enum lttng_error_code send_consumer_relayd_socket( if (status != LTTNG_OK) { goto relayd_comm_error; } - assert(rsock); + LTTNG_ASSERT(rsock); /* Set the network sequence index if not set. */ if (consumer->net_seq_index == (uint64_t) -1ULL) { @@ -1056,8 +1058,8 @@ static enum lttng_error_code send_consumer_relayd_sockets( { enum lttng_error_code status = LTTNG_OK; - assert(consumer); - assert(sock); + LTTNG_ASSERT(consumer); + LTTNG_ASSERT(sock); /* Sending control relayd socket. */ if (!sock->control_sock_sent) { @@ -1101,7 +1103,7 @@ int cmd_setup_relayd(struct ltt_session *session) struct lttng_ht_iter iter; LTTNG_OPTIONAL(uint64_t) current_chunk_id = {}; - assert(session); + LTTNG_ASSERT(session); usess = session->ust_session; ksess = session->kernel_session; @@ -1366,9 +1368,9 @@ int cmd_enable_channel(struct ltt_session *session, size_t len; struct lttng_channel attr; - assert(session); - assert(_attr); - assert(domain); + LTTNG_ASSERT(session); + LTTNG_ASSERT(_attr); + LTTNG_ASSERT(domain); attr = *_attr; len = lttng_strnlen(attr.name, sizeof(attr.name)); @@ -1384,15 +1386,6 @@ int cmd_enable_channel(struct ltt_session *session, rcu_read_lock(); - /* - * Don't try to enable a channel if the session has been started at - * some point in time before. The tracer does not allow it. - */ - if (session->has_been_started) { - ret = LTTNG_ERR_TRACE_ALREADY_STARTED; - goto error; - } - /* * If the session is a live session, remove the switch timer, the * live timer does the same thing but sends also synchronisation @@ -1441,6 +1434,15 @@ int cmd_enable_channel(struct ltt_session *session, kchan = trace_kernel_get_channel_by_name(attr.name, session->kernel_session); if (kchan == NULL) { + /* + * Don't try to create a channel if the session has been started at + * some point in time before. The tracer does not allow it. + */ + if (session->has_been_started) { + ret = LTTNG_ERR_TRACE_ALREADY_STARTED; + goto error; + } + if (session->snapshot.nb_output > 0 || session->snapshot_mode) { /* Enforce mmap output for snapshot sessions. */ @@ -1500,6 +1502,15 @@ int cmd_enable_channel(struct ltt_session *session, uchan = trace_ust_find_channel_by_name(chan_ht, attr.name); if (uchan == NULL) { + /* + * Don't try to create a channel if the session has been started at + * some point in time before. The tracer does not allow it. + */ + if (session->has_been_started) { + ret = LTTNG_ERR_TRACE_ALREADY_STARTED; + goto error; + } + ret = channel_ust_create(usess, &attr, domain->buf_type); if (attr.name[0] != '\0') { usess->has_non_default_channel = 1; @@ -1862,7 +1873,7 @@ int cmd_disable_event(struct ltt_session *session, struct agent *agt; struct ltt_ust_session *usess = session->ust_session; - assert(usess); + LTTNG_ASSERT(usess); switch (event->type) { case LTTNG_EVENT_ALL: @@ -1931,7 +1942,7 @@ int cmd_add_context(struct ltt_session *session, enum lttng_domain_type domain, switch (domain) { case LTTNG_DOMAIN_KERNEL: - assert(session->kernel_session); + LTTNG_ASSERT(session->kernel_session); if (session->kernel_session->channel_count == 0) { /* Create default channel */ @@ -1975,7 +1986,7 @@ int cmd_add_context(struct ltt_session *session, enum lttng_domain_type domain, struct ltt_ust_session *usess = session->ust_session; unsigned int chan_count; - assert(usess); + LTTNG_ASSERT(usess); chan_count = lttng_ht_get_count(usess->domain_global.channels); if (chan_count == 0) { @@ -2020,7 +2031,7 @@ error: trace_kernel_get_channel_by_name(DEFAULT_CHANNEL_NAME, session->kernel_session); /* Created previously, this should NOT fail. */ - assert(kchan); + LTTNG_ASSERT(kchan); kernel_destroy_channel(kchan); } @@ -2030,7 +2041,7 @@ error: session->ust_session->domain_global.channels, DEFAULT_CHANNEL_NAME); /* Created previously, this should NOT fail. */ - assert(uchan); + LTTNG_ASSERT(uchan); /* Remove from the channel list of the session. */ trace_ust_delete_channel(session->ust_session->domain_global.channels, uchan); @@ -2090,12 +2101,12 @@ static int _cmd_enable_event(struct ltt_session *session, int ret = 0, channel_created = 0; struct lttng_channel *attr = NULL; - assert(session); - assert(event); - assert(channel_name); + LTTNG_ASSERT(session); + LTTNG_ASSERT(event); + LTTNG_ASSERT(channel_name); /* If we have a filter, we must have its filter expression */ - assert(!(!!filter_expression ^ !!filter)); + LTTNG_ASSERT(!(!!filter_expression ^ !!filter)); /* Normalize event name as a globbing pattern */ strutils_normalize_star_glob_pattern(event->name); @@ -2256,7 +2267,7 @@ static int _cmd_enable_event(struct ltt_session *session, struct ltt_ust_channel *uchan; struct ltt_ust_session *usess = session->ust_session; - assert(usess); + LTTNG_ASSERT(usess); /* * If a non-default channel has been created in the @@ -2293,7 +2304,7 @@ static int _cmd_enable_event(struct ltt_session *session, /* Get the newly created channel reference back */ uchan = trace_ust_find_channel_by_name( usess->domain_global.channels, channel_name); - assert(uchan); + LTTNG_ASSERT(uchan); } if (uchan->domain != LTTNG_DOMAIN_UST && !internal_event) { @@ -2345,7 +2356,7 @@ static int _cmd_enable_event(struct ltt_session *session, struct lttng_domain tmp_dom; struct ltt_ust_session *usess = session->ust_session; - assert(usess); + LTTNG_ASSERT(usess); if (!agent_tracing_is_enabled()) { DBG("Attempted to enable an event in an agent domain but the agent thread is not running"); @@ -2396,7 +2407,7 @@ static int _cmd_enable_event(struct ltt_session *session, break; default: /* The switch/case we are in makes this impossible */ - assert(0); + abort(); } { @@ -2602,7 +2613,7 @@ int cmd_start_trace(struct ltt_session *session) const bool session_cleared_after_last_stop = session->cleared_after_last_stop; - assert(session); + LTTNG_ASSERT(session); /* Ease our life a bit ;) */ ksession = session->kernel_session; @@ -2661,7 +2672,7 @@ int cmd_start_trace(struct ltt_session *session) ret = LTTNG_ERR_CREATE_DIR_FAIL; goto error; } - assert(!session->current_trace_chunk); + LTTNG_ASSERT(!session->current_trace_chunk); ret = session_set_trace_chunk(session, trace_chunk, NULL); lttng_trace_chunk_put(trace_chunk); @@ -2763,7 +2774,7 @@ int cmd_stop_trace(struct ltt_session *session) struct ltt_kernel_session *ksession; struct ltt_ust_session *usess; - assert(session); + LTTNG_ASSERT(session); DBG("Begin stop session \"%s\" (id %" PRIu64 ")", session->name, session->id); /* Short cut */ @@ -2848,9 +2859,9 @@ int cmd_set_consumer_uri(struct ltt_session *session, size_t nb_uri, struct ltt_kernel_session *ksess = session->kernel_session; struct ltt_ust_session *usess = session->ust_session; - assert(session); - assert(uris); - assert(nb_uri > 0); + LTTNG_ASSERT(session); + LTTNG_ASSERT(uris); + LTTNG_ASSERT(nb_uri > 0); /* Can't set consumer URI if the session is active. */ if (session->active) { @@ -3238,6 +3249,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); @@ -3285,7 +3297,7 @@ int cmd_destroy_session(struct ltt_session *session, } /* Safety net */ - assert(session); + LTTNG_ASSERT(session); DBG("Begin destroy session %s (id %" PRIu64 ")", session->name, session->id); @@ -3408,7 +3420,7 @@ int cmd_destroy_session(struct ltt_session *session, ret = lttng_strncpy(destroy_completion_handler.shm_path, session->shm_path, sizeof(destroy_completion_handler.shm_path)); - assert(!ret); + LTTNG_ASSERT(!ret); } /* @@ -3444,16 +3456,16 @@ int cmd_register_consumer(struct ltt_session *session, int ret, sock; struct consumer_socket *socket = NULL; - assert(session); - assert(cdata); - assert(sock_path); + LTTNG_ASSERT(session); + LTTNG_ASSERT(cdata); + LTTNG_ASSERT(sock_path); switch (domain) { case LTTNG_DOMAIN_KERNEL: { struct ltt_kernel_session *ksess = session->kernel_session; - assert(ksess); + LTTNG_ASSERT(ksess); /* Can't register a consumer if there is already one */ if (ksess->consumer_fds_sent != 0) { @@ -3798,7 +3810,7 @@ int cmd_data_pending(struct ltt_session *session) struct ltt_kernel_session *ksess = session->kernel_session; struct ltt_ust_session *usess = session->ust_session; - assert(session); + LTTNG_ASSERT(session); DBG("Data pending for session %s", session->name); @@ -3864,8 +3876,8 @@ int cmd_snapshot_add_output(struct ltt_session *session, int ret; struct snapshot_output *new_output; - assert(session); - assert(output); + LTTNG_ASSERT(session); + LTTNG_ASSERT(output); DBG("Cmd snapshot add output for session %s", session->name); @@ -3932,8 +3944,8 @@ int cmd_snapshot_del_output(struct ltt_session *session, int ret; struct snapshot_output *sout = NULL; - assert(session); - assert(output); + LTTNG_ASSERT(session); + LTTNG_ASSERT(output); rcu_read_lock(); @@ -3984,8 +3996,8 @@ ssize_t cmd_snapshot_list_outputs(struct ltt_session *session, struct lttng_ht_iter iter; struct snapshot_output *output; - assert(session); - assert(outputs); + LTTNG_ASSERT(session); + LTTNG_ASSERT(outputs); DBG("Cmd snapshot list outputs for session %s", session->name); @@ -4013,7 +4025,7 @@ ssize_t cmd_snapshot_list_outputs(struct ltt_session *session, rcu_read_lock(); cds_lfht_for_each_entry(session->snapshot.output_ht->ht, &iter.iter, output, node.node) { - assert(output->consumer); + LTTNG_ASSERT(output->consumer); list[idx].id = output->id; list[idx].max_size = output->max_size; if (lttng_strncpy(list[idx].name, output->name, @@ -4069,7 +4081,7 @@ int check_regenerate_metadata_support(struct ltt_session *session) { int ret; - assert(session); + LTTNG_ASSERT(session); if (session->live_timer != 0) { ret = LTTNG_ERR_LIVE_SESSION; @@ -4087,7 +4099,7 @@ int check_regenerate_metadata_support(struct ltt_session *session) ret = LTTNG_ERR_PER_PID_SESSION; goto end; default: - assert(0); + abort(); ret = LTTNG_ERR_UNK; goto end; } @@ -4209,7 +4221,7 @@ int cmd_regenerate_metadata(struct ltt_session *session) { int ret; - assert(session); + LTTNG_ASSERT(session); ret = check_regenerate_metadata_support(session); if (ret) { @@ -4250,7 +4262,7 @@ int cmd_regenerate_statedump(struct ltt_session *session) { int ret; - assert(session); + LTTNG_ASSERT(session); if (!session->active) { ret = LTTNG_ERR_SESSION_NOT_STARTED; @@ -4293,42 +4305,111 @@ end: return ret; } -static enum lttng_error_code trigger_modifies_event_notifier( - const struct lttng_trigger *trigger, bool *adds_event_notifier) +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) { - enum lttng_error_code ret_code = LTTNG_OK; - const struct lttng_condition *condition = NULL; + 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); - condition = lttng_trigger_get_const_condition(trigger); - if (!condition) { - ret_code = LTTNG_ERR_INVALID_TRIGGER; - goto end; + trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_owner); + LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + LTTNG_ASSERT(condition); + LTTNG_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)"; + + 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); - *adds_event_notifier = lttng_condition_get_type(condition) == - LTTNG_CONDITION_TYPE_EVENT_RULE_HIT; -end: + 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; - bool must_update_event_notifiers; 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 : "(unnamed)"; + trigger_name : "(anonymous)"; trigger_status = lttng_trigger_get_owner_uid( trigger, &trigger_owner); - assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + LTTNG_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, @@ -4372,8 +4453,8 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c * it is safe to use without any locking as its properties are * immutable. */ - ret_code = notification_thread_command_register_trigger(notification_thread, - trigger); + 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); @@ -4382,74 +4463,19 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c trigger_status = lttng_trigger_get_name(trigger, &trigger_name); trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? - trigger_name : "(unnamed)"; - - ret_code = trigger_modifies_event_notifier(trigger, &must_update_event_notifiers); - if (ret_code != LTTNG_OK) { - ERR("Failed to determine if event modifies event notifiers: trigger name = '%s', trigger owner uid = %d, error code = %d", - trigger_name, (int) trigger_owner, ret_code); - goto end; - } + trigger_name : "(anonymous)"; /* * Synchronize tracers if the trigger adds an event notifier. */ - if (must_update_event_notifiers) { - const enum lttng_domain_type trigger_domain = - lttng_trigger_get_underlying_domain_type_restriction(trigger); - - session_lock_list(); - switch (trigger_domain) { - case LTTNG_DOMAIN_KERNEL: - { - ret_code = kernel_register_event_notifier( - trigger, cmd_creds); - if (ret_code != LTTNG_OK) { - const enum lttng_error_code 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_NONE: - abort(); - default: - { - /* 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, trigger_agents_ht_by_domain); - } - - ret_code = trigger_agent_enable(trigger, agt); - if (ret_code != LTTNG_OK) { - goto end_unlock_session_list; - } - - break; - } + 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; } - - session_unlock_list(); } /* @@ -4467,6 +4493,62 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c } 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); + + LTTNG_ASSERT(condition); + LTTNG_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: + { + /* 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. + */ + LTTNG_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; @@ -4477,16 +4559,15 @@ enum lttng_error_code cmd_unregister_trigger(const struct lttng_credentials *cmd struct notification_thread_handle *notification_thread) { enum lttng_error_code ret_code; - bool must_update_event_notifiers; 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 : "(unnamed)"; - trigger_status = lttng_trigger_get_owner_uid( - trigger, &trigger_owner); - assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? trigger_name : "(anonymous)"; + trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_owner); + LTTNG_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, @@ -4509,18 +4590,34 @@ enum lttng_error_code cmd_unregister_trigger(const struct lttng_credentials *cmd } } - ret_code = trigger_modifies_event_notifier(trigger, &must_update_event_notifiers); + /* Fetch the sessiond side trigger object. */ + ret_code = notification_thread_command_get_trigger( + notification_thread, trigger, &sessiond_trigger); if (ret_code != LTTNG_OK) { - ERR("Failed to determine if event modifies event notifiers: trigger name = '%s', trigger owner uid = %d, error code = %d", + 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; } + LTTNG_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; } /* @@ -4529,62 +4626,25 @@ enum lttng_error_code cmd_unregister_trigger(const struct lttng_credentials *cmd * the tracers from producing notifications associated with this * event notifier. */ - if (must_update_event_notifiers) { - const enum lttng_domain_type trigger_domain = - lttng_trigger_get_underlying_domain_type_restriction( - trigger); - - session_lock_list(); - switch (trigger_domain) { - case LTTNG_DOMAIN_KERNEL: - { - ret_code = kernel_unregister_event_notifier( - trigger); - break; - } - case LTTNG_DOMAIN_UST: - ust_app_global_update_all_event_notifier_rules(); - break; - case LTTNG_DOMAIN_NONE: - abort(); - default: - { - /* 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, trigger_agents_ht_by_domain); - } - - ret_code = trigger_agent_disable(trigger, agt); - if (ret_code != LTTNG_OK) { - goto end_unlock_session_list; - } - - break; - } + 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; } - session_unlock_list(); } end: + lttng_trigger_put(sessiond_trigger); return ret_code; -end_unlock_session_list: - session_unlock_list(); - return ret_code;} +} -int cmd_list_triggers(struct command_ctx *cmd_ctx, +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 = 0; + int ret; enum lttng_error_code ret_code; struct lttng_triggers *triggers = NULL; @@ -4592,17 +4652,165 @@ int cmd_list_triggers(struct command_ctx *cmd_ctx, ret_code = notification_thread_command_list_triggers( notification_thread, cmd_ctx->creds.uid, &triggers); if (ret_code != LTTNG_OK) { - ret = ret_code; + goto end; + } + + ret = lttng_triggers_remove_hidden_triggers(triggers); + if (ret) { + ret_code = LTTNG_ERR_UNK; goto end; } *return_triggers = triggers; triggers = NULL; - ret = LTTNG_OK; + ret_code = LTTNG_OK; end: lttng_triggers_destroy(triggers); - return ret; + 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(); + } + + LTTNG_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; + } + + /* 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); + } + + 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); + LTTNG_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 target a trigger with non-matching + * credentials. + */ + if (!lttng_credentials_is_equal_uid( + 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; + } + + *_results = results; + results = NULL; + ret_code = LTTNG_OK; +end: + lttng_trigger_put(matching_trigger); + lttng_error_query_results_destroy(results); + return ret_code; +} + /* * Send relayd sockets from snapshot output to consumer. Ignore request if the * snapshot output is *not* set with a remote destination. @@ -4619,8 +4827,8 @@ static enum lttng_error_code set_relayd_for_snapshot( LTTNG_OPTIONAL(uint64_t) current_chunk_id = {}; const char *base_path; - assert(output); - assert(session); + LTTNG_ASSERT(output); + LTTNG_ASSERT(session); DBG2("Set relayd object from snapshot output"); @@ -4695,9 +4903,9 @@ static enum lttng_error_code record_kernel_snapshot( { enum lttng_error_code status; - assert(ksess); - assert(output); - assert(session); + LTTNG_ASSERT(ksess); + LTTNG_ASSERT(output); + LTTNG_ASSERT(session); status = kernel_snapshot_record( ksess, output, wait, nb_packets_per_stream); @@ -4716,9 +4924,9 @@ static enum lttng_error_code record_ust_snapshot(struct ltt_ust_session *usess, { enum lttng_error_code status; - assert(usess); - assert(output); - assert(session); + LTTNG_ASSERT(usess); + LTTNG_ASSERT(output); + LTTNG_ASSERT(session); status = ust_app_snapshot_record( usess, output, wait, nb_packets_per_stream); @@ -4853,6 +5061,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) { @@ -4875,6 +5088,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) { @@ -4904,7 +5122,7 @@ enum lttng_error_code snapshot_record(struct ltt_session *session, ret_code = LTTNG_ERR_CREATE_DIR_FAIL; goto error; } - assert(!session->current_trace_chunk); + LTTNG_ASSERT(!session->current_trace_chunk); ret = session_set_trace_chunk(session, snapshot_trace_chunk, NULL); lttng_trace_chunk_put(snapshot_trace_chunk); snapshot_trace_chunk = NULL; @@ -4987,8 +5205,8 @@ int cmd_snapshot_record(struct ltt_session *session, char datetime[16]; struct snapshot_output *tmp_output = NULL; - assert(session); - assert(output); + LTTNG_ASSERT(session); + LTTNG_ASSERT(output); DBG("Cmd snapshot record for session %s", session->name); @@ -5111,7 +5329,7 @@ int cmd_set_session_shm_path(struct ltt_session *session, const char *shm_path) { /* Safety net */ - assert(session); + LTTNG_ASSERT(session); /* * Can only set shm path before session is started. @@ -5149,7 +5367,7 @@ int cmd_rotate_session(struct ltt_session *session, bool failed_to_rotate = false; enum lttng_error_code rotation_fail_code = LTTNG_OK; - assert(session); + LTTNG_ASSERT(session); if (!session->has_been_started) { cmd_ret = LTTNG_ERR_START_SESSION_ONCE; @@ -5267,7 +5485,7 @@ int cmd_rotate_session(struct ltt_session *session, session->rotation_state = LTTNG_ROTATION_STATE_ONGOING; chunk_status = lttng_trace_chunk_get_id(chunk_being_archived, &ongoing_rotation_chunk_id); - assert(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK); + LTTNG_ASSERT(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK); ret = session_close_trace_chunk(session, chunk_being_archived, command, session->last_chunk_path); @@ -5297,8 +5515,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", @@ -5347,7 +5565,7 @@ int cmd_rotate_get_info(struct ltt_session *session, chunk_status = lttng_trace_chunk_get_id( session->chunk_being_archived, &chunk_id); - assert(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK); + LTTNG_ASSERT(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK); rotation_state = rotation_id == chunk_id ? LTTNG_ROTATION_STATE_ONGOING : @@ -5487,7 +5705,7 @@ int cmd_rotation_set_schedule(struct ltt_session *session, int ret; uint64_t *parameter_value; - assert(session); + LTTNG_ASSERT(session); DBG("Cmd rotate set schedule session %s", session->name);