#include <lttng/location-internal.h>
#include <lttng/trigger/trigger-internal.h>
#include <lttng/condition/condition.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/condition/event-rule-internal.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/uprobe-internal.h>
+#include <lttng/event-rule/tracepoint.h>
#include <lttng/action/action.h>
#include <lttng/channel.h>
#include <lttng/channel-internal.h>
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);
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)
{
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,
{
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);
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)
{
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)
{
return ret;
}
+/*
+ * On success LTTNG_OK. On error, returns lttng_error code.
+ */
+static enum lttng_error_code prepare_trigger_object(struct lttng_trigger *trigger, const struct lttng_credentials *cmd_creds)
+{
+ enum lttng_error_code ret;
+ /* Internal object of the trigger might have to "generate" and
+ * "populate" internal field e.g filter bytecode
+ */
+ struct lttng_condition *condition = NULL;
+
+ condition = lttng_trigger_get_condition(trigger);
+ if (!condition) {
+ ret = LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+
+ switch (lttng_condition_get_type(condition)) {
+ case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+ {
+ struct lttng_event_rule *event_rule;
+ lttng_condition_event_rule_get_rule_mutable(
+ condition, &event_rule);
+ ret = lttng_event_rule_generate_filter_bytecode(
+ event_rule, lttng_credentials_get_uid(cmd_creds), lttng_credentials_get_gid(cmd_creds));
+ if (ret != LTTNG_OK) {
+ goto end;
+ }
+
+ /* Generate the capture bytecode set */
+ ret = lttng_condition_event_rule_generate_capture_descriptor_bytecode_set(
+ condition, &trigger->capture_bytecode_set);
+ if (ret != LTTNG_OK) {
+ goto end;
+ }
+
+ ret = LTTNG_OK;
+ break;
+ }
+ default:
+ {
+ ret = LTTNG_OK;
+ break;
+ }
+ }
+
+end:
+ return ret;
+}
+
int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
- struct notification_thread_handle *notification_thread)
+ struct notification_thread_handle *notification_thread,
+ struct lttng_trigger **return_trigger)
{
int ret;
size_t trigger_len;
struct lttng_trigger *trigger = NULL;
struct lttng_payload trigger_payload;
struct lttng_credentials cmd_creds = {
- .uid = cmd_ctx->creds.uid,
- .gid = cmd_ctx->creds.gid,
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid),
+ .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid),
};
lttng_payload_init(&trigger_payload);
}
}
- /* Set the trigger credential */
- lttng_trigger_set_credentials(trigger, &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");
+ ret = LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+ }
+
+ /*
+ * Since we return the trigger object, take a reference to it
+ * Caller is responsible for calling lttng_destroy_trigger on it.
+ * This thread does not OWN the trigger.
+ */
+ lttng_trigger_get(trigger);
+
+ /* Prepare internal trigger object if needed on reception.
+ * Handles also special treatment for certain internal object of the
+ * trigger (e.g uprobe event rule binary fd.
+ */
+ ret = prepare_trigger_object(trigger, &cmd_creds);
+ if (ret != LTTNG_OK) {
+ goto end;
+ }
/* Inform the notification thread */
ret = notification_thread_command_register_trigger(notification_thread,
trigger);
- /* Ownership of trigger was transferred. */
+ if (ret != LTTNG_OK) {
+ goto end;
+ }
+
+ /* Synchronize tracers, only if needed */
+ /* TODO: maybe extract somewhere else */
+ {
+ struct lttng_condition *condition = NULL;
+ condition = lttng_trigger_get_condition(trigger);
+ if (!condition) {
+ ret = LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+
+ if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+ const struct lttng_event_rule *rule = NULL;
+ (void) lttng_condition_event_rule_get_rule(condition, &rule);
+ if (!rule) {
+ ret = LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+ if (lttng_event_rule_get_domain_type(rule) == LTTNG_DOMAIN_KERNEL) {
+ /* TODO: get the token value from the
+ * notification thread and only perform an
+ * enable and a disable.... This is NOT
+ * OPTIMIZED AT ALL
+ */
+ ret = kernel_register_trigger(trigger, &cmd_creds);
+ if (ret != LTTNG_OK) {
+ enum lttng_error_code notif_thread_unregister_ret =
+ notification_thread_command_unregister_trigger(
+ notification_thread,
+ trigger);
+ if (notif_thread_unregister_ret != LTTNG_OK) {
+ ERR("Error unregistering notification thread trigger after kernel registration failure.");
+ }
+ goto end;
+
+ }
+ } else {
+ /* TODO: get the token value from the
+ * notification thread and only perform an
+ * enable and a disable.... This is NOT
+ * OPTIMIZED AT ALL
+ */
+ ust_app_global_update_all_tokens();
+ /* Agent handling */
+ if (lttng_event_rule_is_agent(rule)) {
+ struct agent *agt;
+ const char *pattern;
+ enum lttng_domain_type domain_type;
+ domain_type = lttng_event_rule_get_domain_type(
+ rule);
+ (void) lttng_event_rule_tracepoint_get_pattern(
+ rule, &pattern);
+ agt = trigger_find_agent(domain_type);
+ if (!agt) {
+ agt = agent_create(domain_type);
+ if (!agt) {
+ ret = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+ agent_add(agt, trigger_agents_ht_by_domain);
+ }
+
+ ret = trigger_agent_enable(
+ trigger, agt);
+ if (ret != LTTNG_OK) {
+ goto end;
+ }
+ }
+ }
+ }
+ }
+
+ /* Return an image of the updated object to the client */
+ *return_trigger = trigger;
+ /* Ownership of trigger was transferred to caller. */
trigger = NULL;
end:
lttng_trigger_destroy(trigger);
struct lttng_trigger *trigger = NULL;
struct lttng_payload trigger_payload;
struct lttng_credentials cmd_creds = {
- .uid = cmd_ctx->creds.uid,
- .gid = cmd_ctx->creds.gid,
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid),
+ .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid),
};
lttng_payload_init(&trigger_payload);
}
}
- lttng_trigger_set_credentials(trigger, &cmd_creds);
+ /*
+ * Validate the trigger credentials against the command credentials.
+ * 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;
+ goto end;
+ }
+ }
+
+ ret = prepare_trigger_object(trigger, &cmd_creds);
+ if (ret != LTTNG_OK) {
+ goto end;
+ }
ret = notification_thread_command_unregister_trigger(notification_thread,
trigger);
+
+ /* Synchronize tracers, only if needed */
+ /* TODO: maybe extract somewhere else */
+ {
+ struct lttng_condition *condition = NULL;
+ condition = lttng_trigger_get_condition(trigger);
+ if (!condition) {
+ ret = LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+
+ if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+ const struct lttng_event_rule *rule = NULL;
+ (void) lttng_condition_event_rule_get_rule(condition, &rule);
+ if (!rule) {
+ ret = LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+ if (lttng_event_rule_get_domain_type(rule) == LTTNG_DOMAIN_KERNEL) {
+ /* TODO: get the token value from the
+ * notification thread and only perform an
+ * enable and a disable.... This is NOT
+ * OPTIMIZED AT ALL
+ */
+ ret = kernel_unregister_trigger(trigger);
+ } else {
+ /* TODO: get the token value from the
+ * notification thread and only perform an
+ * enable and a disable.... This is NOT
+ * OPTIMIZED AT ALL
+ */
+ ust_app_global_update_all_tokens();
+ if (lttng_event_rule_is_agent(rule)) {
+ struct agent *agt;
+ const char *pattern;
+ enum lttng_domain_type domain_type;
+
+ domain_type = lttng_event_rule_get_domain_type(
+ rule);
+ (void) lttng_event_rule_tracepoint_get_pattern(
+ rule, &pattern);
+
+ agt = trigger_find_agent(domain_type);
+ if (!agt) {
+ ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
+ goto end;
+ }
+ ret = trigger_agent_disable(
+ trigger, agt);
+ if (ret != LTTNG_OK) {
+ goto end;
+ }
+ }
+ }
+ }
+ }
+
end:
lttng_trigger_destroy(trigger);
lttng_payload_reset(&trigger_payload);
return ret;
}
+int cmd_list_triggers(struct command_ctx *cmd_ctx,
+ struct notification_thread_handle *notification_thread,
+ struct lttng_triggers **return_triggers)
+{
+ int ret = 0;
+ enum lttng_error_code ret_code;
+ struct lttng_triggers *triggers = NULL;
+
+ /* Get list of token trigger from the notification thread here */
+ ret_code = notification_thread_command_list_triggers(notification_thread, cmd_ctx->creds.uid, &triggers);
+ if (ret_code != LTTNG_OK) {
+ ret = ret_code;
+ goto end;
+ }
+
+ /* Return a "view" of the current triggers */
+ *return_triggers = triggers;
+ triggers = NULL;
+ ret = LTTNG_OK;
+end:
+ lttng_triggers_destroy(triggers);
+ return ret;
+}
/*
* Send relayd sockets from snapshot output to consumer. Ignore request if the
* snapshot output is *not* set with a remote destination.