SoW-2019-0002: Dynamic Snapshot
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index 5e522d6fe0886108b87df756e930a6519a5a8a09..f4c7390ef784d52d9371d982e78a68dab966e358 100644 (file)
 #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>
@@ -4283,8 +4290,94 @@ end:
        return ret;
 }
 
+/* TODO: is this the best place to perform this? (code wise) */
+/*
+ * Set sock to -1 if reception of more information is not necessary e.g on
+ * unregister. TODO find a better way.
+ *
+ * On success LTTNG_OK. On error, returns lttng_error code.
+ * */
+static enum lttng_error_code prepare_trigger_object(struct lttng_trigger *trigger, int sock)
+{
+       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;
+               const struct lttng_credentials *credential = lttng_trigger_get_credentials(trigger);
+               lttng_condition_event_rule_get_rule_no_const(
+                               condition, &event_rule);
+               ret = lttng_event_rule_populate(event_rule, credential->uid, credential->gid);
+               if (ret != LTTNG_OK) {
+                       goto end;
+               }
+
+               switch (lttng_event_rule_get_type(event_rule)) {
+               case LTTNG_EVENT_RULE_TYPE_UPROBE:
+               {
+                       int fd;
+                       struct lttng_userspace_probe_location *location = lttng_event_rule_uprobe_get_location_no_const(event_rule);
+
+                       if (sock < 0) {
+                               /* Nothing to receive */
+                               break;
+                       }
+                       /*
+                        * 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");
+                               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+                               goto end;
+                       }
+
+                       /*
+                        * Set the file descriptor received from the client
+                        * through the unix socket in the probe location.
+                        */
+                       ret = lttng_userspace_probe_location_set_binary_fd(
+                                       location, fd);
+                       if (ret) {
+                               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+                               goto end;
+                       }
+
+                       break;
+               }
+               default:
+                       /* Nothing to do */
+                       break;
+               }
+               ret = LTTNG_OK;
+               break;
+       }
+       default:
+       {
+               ret = LTTNG_OK;
+               break;
+       }
+       }
+end:
+       return ret;
+}
+
+/* Caller must call lttng_destroy_trigger on the returned trigger object */
 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;
@@ -4318,9 +4411,95 @@ int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
                goto end;
        }
 
+       /* Set the trigger credential */
+       lttng_trigger_set_credentials(trigger, cmd_ctx->creds.uid, cmd_ctx->creds.gid);
+
+       /* 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, sock);
+       if (ret != LTTNG_OK) {
+               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);
+
+       /* 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
+                                */
+                               kernel_update_tokens();
+                       } 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);
@@ -4363,14 +4542,110 @@ int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock,
                goto end;
        }
 
+       lttng_trigger_set_credentials(trigger, cmd_ctx->creds.uid, cmd_ctx->creds.gid);
+
+       /* TODO: forgotting this bited me for agent since the filter is
+        * genereted on this side. Wonder if we could find a way to detect when
+        * do it or not.
+        */
+
+       /* 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, -1);
+       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
+                                */
+                               kernel_update_tokens();
+                       } 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_dynamic_buffer_reset(&trigger_buffer);
        return ret;
 }
 
+int cmd_list_triggers(struct command_ctx *cmd_ctx, int sock,
+               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_handle, cmd_ctx->creds.uid, cmd_ctx->creds.gid, &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.
This page took 0.027689 seconds and 5 git commands to generate.