Build fix: retrieve unix socket peer PID on non-unix platforms
[lttng-tools.git] / src / common / error-query.c
index 031257b27ec6e7d4bed66648dfbbe0ca8b47708a..2eb1c971715902767e6550c2971d7026c346c6b5 100644 (file)
 #include <common/dynamic-array.h>
 #include <common/error.h>
 #include <common/macros.h>
+#include <common/mi-lttng.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <lttng/action/action-internal.h>
-#include <lttng/action/group-internal.h>
+#include <lttng/action/list-internal.h>
+#include <lttng/action/path-internal.h>
 #include <lttng/error-query-internal.h>
 #include <lttng/error-query.h>
 #include <lttng/trigger/trigger-internal.h>
@@ -35,23 +37,17 @@ struct lttng_error_query_trigger {
        struct lttng_trigger *trigger;
 };
 
-struct lttng_error_query_action_comm {
-       LTTNG_OPTIONAL_COMM(uint32_t) action_index;
-       /* Trigger payload. */
-       char payload[];
+struct lttng_error_query_condition {
+       struct lttng_error_query parent;
+       /* Mutable only because of the reference count. */
+       struct lttng_trigger *trigger;
 };
 
 struct lttng_error_query_action {
        struct lttng_error_query parent;
        /* Mutable only because of the reference count. */
        struct lttng_trigger *trigger;
-       /*
-        * Index of the target action. Since action lists can't be nested,
-        * the targetted action is the top-level group if the action_index is
-        * unset. Otherwise, the index refers to the index within the top-level
-        * group.
-        */
-       LTTNG_OPTIONAL(unsigned int) action_index;
+       struct lttng_action_path action_path;
 };
 
 struct lttng_error_query_result {
@@ -90,6 +86,15 @@ struct lttng_error_query_results {
        struct lttng_dynamic_pointer_array results;
 };
 
+static
+enum lttng_error_code lttng_error_query_result_mi_serialize(
+               const struct lttng_error_query_result *result,
+               struct mi_writer *writer);
+
+static
+enum lttng_error_code lttng_error_query_result_counter_mi_serialize(
+               const struct lttng_error_query_result *result,
+               struct mi_writer *writer);
 
 struct lttng_error_query *lttng_error_query_trigger_create(
                const struct lttng_trigger *trigger)
@@ -122,15 +127,13 @@ end:
        return query ? &query->parent : NULL;
 }
 
-extern struct lttng_error_query *lttng_error_query_action_create(
-               const struct lttng_trigger *trigger,
-               const struct lttng_action *action)
+struct lttng_error_query *lttng_error_query_condition_create(
+               const struct lttng_trigger *trigger)
 {
-       struct lttng_error_query_action *query = NULL;
-       typeof(query->action_index) action_index;
+       struct lttng_error_query_condition *query = NULL;
        struct lttng_trigger *trigger_copy = NULL;
 
-       if (!trigger || !action) {
+       if (!trigger) {
                goto end;
        }
 
@@ -139,49 +142,83 @@ extern struct lttng_error_query *lttng_error_query_action_create(
                goto end;
        }
 
+       query = zmalloc(sizeof(*query));
+       if (!query) {
+               PERROR("Failed to allocate condition error query");
+               goto error;
+       }
+
+       query->parent.target_type = LTTNG_ERROR_QUERY_TARGET_TYPE_CONDITION;
+       query->trigger = trigger_copy;
+       trigger_copy = NULL;
+
+error:
+       lttng_trigger_put(trigger_copy);
+end:
+       return query ? &query->parent : NULL;
+}
+
+static
+struct lttng_action *get_trigger_action_from_path(
+               struct lttng_trigger *trigger,
+               const struct lttng_action_path *action_path)
+{
+       size_t index_count, i;
+       enum lttng_action_path_status path_status;
+       struct lttng_action *current_action = NULL;
+
+       path_status = lttng_action_path_get_index_count(
+                       action_path, &index_count);
+       if (path_status != LTTNG_ACTION_PATH_STATUS_OK) {
+               goto end;
+       }
+
+       current_action = lttng_trigger_get_action(trigger);
+       for (i = 0; i < index_count; i++) {
+               uint64_t path_index;
+
+               path_status = lttng_action_path_get_index_at_index(
+                               action_path, i, &path_index);
+               current_action = lttng_action_list_borrow_mutable_at_index(
+                               current_action, path_index);
+               if (!current_action) {
+                       /* Invalid action path. */
+                       goto end;
+               }
+       }
+
+end:
+       return current_action;
+}
+
+static
+bool is_valid_action_path(const struct lttng_trigger *trigger,
+               const struct lttng_action_path *action_path)
+{
        /*
-        * If an action is not the top-level action of the trigger, our only
-        * hope of finding its position is if the top-level action is an
-        * action list.
-        *
-        * Note that action comparisons are performed by pointer since multiple
-        * otherwise identical actions can be found in an action group (two
-        * notify actions, for example).
+        * While 'trigger's constness is casted-away, the trigger and resulting
+        * action are not modified; we merely check for the action's existence.
         */
-       if (action != trigger->action &&
-                       lttng_action_get_type(trigger->action) ==
-                                       LTTNG_ACTION_TYPE_GROUP) {
-               unsigned int i, action_group_count;
-               enum lttng_action_status action_status;
-
-               action_status = lttng_action_group_get_count(
-                               trigger->action, &action_group_count);
-               if (action_status != LTTNG_ACTION_STATUS_OK) {
-                       goto error;
-               }
+       return !!get_trigger_action_from_path(
+                       (struct lttng_trigger *) trigger, action_path);
+}
 
-               for (i = 0; i < action_group_count; i++) {
-                       const struct lttng_action *candidate_action =
-                                       lttng_action_group_get_at_index(
-                                                       trigger->action, i);
+struct lttng_error_query *lttng_error_query_action_create(
+               const struct lttng_trigger *trigger,
+               const struct lttng_action_path *action_path)
+{
+       struct lttng_error_query_action *query = NULL;
+       struct lttng_trigger *trigger_copy = NULL;
+       int ret_copy;
 
-                       assert(candidate_action);
-                       if (candidate_action == action) {
-                               LTTNG_OPTIONAL_SET(&action_index, i);
-                               break;
-                       }
-               }
+       if (!trigger || !action_path ||
+                       !is_valid_action_path(trigger, action_path)) {
+               goto end;
+       }
 
-               if (!action_index.is_set) {
-                       /* Not found; invalid action. */
-                       goto error;
-               }
-       } else {
-               /*
-                * Trigger action is not a group and not equal to the target
-                * action; invalid action provided.
-                */
-               goto error;
+       trigger_copy = lttng_trigger_copy(trigger);
+       if (!trigger_copy) {
+               goto end;
        }
 
        query = zmalloc(sizeof(*query));
@@ -190,12 +227,19 @@ extern struct lttng_error_query *lttng_error_query_action_create(
                goto error;
        }
 
+       ret_copy = lttng_action_path_copy(action_path, &query->action_path);
+       if (ret_copy) {
+               goto error;
+       }
+
        query->parent.target_type = LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION;
        query->trigger = trigger_copy;
        trigger_copy = NULL;
-       query->action_index = action_index;
+       goto end;
+
 error:
        lttng_trigger_put(trigger_copy);
+       lttng_error_query_destroy(query ? &query->parent : NULL);
 end:
        return query ? &query->parent : NULL;
 }
@@ -608,6 +652,28 @@ end:
        return ret;
 }
 
+static
+int lttng_error_query_condition_serialize(const struct lttng_error_query *query,
+               struct lttng_payload *payload)
+{
+       int ret;
+       const struct lttng_error_query_condition *query_trigger =
+                       container_of(query, typeof(*query_trigger), parent);
+
+       if (!lttng_trigger_validate(query_trigger->trigger)) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = lttng_trigger_serialize(query_trigger->trigger, payload);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
 static
 int lttng_error_query_action_serialize(const struct lttng_error_query *query,
                struct lttng_payload *payload)
@@ -615,26 +681,22 @@ int lttng_error_query_action_serialize(const struct lttng_error_query *query,
        int ret;
        const struct lttng_error_query_action *query_action =
                        container_of(query, typeof(*query_action), parent);
-       struct lttng_error_query_action_comm header = {
-               .action_index.is_set = query_action->action_index.is_set,
-               .action_index.value = query_action->action_index.value,
-       };
 
        if (!lttng_trigger_validate(query_action->trigger)) {
                ret = -1;
                goto end;
        }
 
-       ret = lttng_dynamic_buffer_append(
-                       &payload->buffer, &header, sizeof(header));
+       ret = lttng_trigger_serialize(query_action->trigger, payload);
        if (ret) {
                goto end;
        }
 
-       ret = lttng_trigger_serialize(query_action->trigger, payload);
+       ret = lttng_action_path_serialize(&query_action->action_path, payload);
        if (ret) {
                goto end;
        }
+
 end:
        return ret;
 }
@@ -656,6 +718,16 @@ const struct lttng_trigger *lttng_error_query_trigger_borrow_target(
        return query_trigger->trigger;
 }
 
+LTTNG_HIDDEN
+const struct lttng_trigger *lttng_error_query_condition_borrow_target(
+               const struct lttng_error_query *query)
+{
+       const struct lttng_error_query_condition *query_trigger =
+                       container_of(query, typeof(*query_trigger), parent);
+
+       return query_trigger->trigger;
+}
+
 LTTNG_HIDDEN
 const struct lttng_trigger *lttng_error_query_action_borrow_trigger_target(
                const struct lttng_error_query *query)
@@ -671,28 +743,11 @@ struct lttng_action *lttng_error_query_action_borrow_action_target(
        const struct lttng_error_query *query,
        struct lttng_trigger *trigger)
 {
-       struct lttng_action *target_action = NULL;
        const struct lttng_error_query_action *query_action =
                        container_of(query, typeof(*query_action), parent);
-       struct lttng_action *trigger_action =
-                       lttng_trigger_get_action(trigger);
-
-       if (!query_action->action_index.is_set) {
-               target_action = trigger_action;
-       } else {
-               if (lttng_action_get_type(trigger_action) !=
-                               LTTNG_ACTION_TYPE_GROUP) {
-                       ERR("Invalid action error query target index: trigger action is not a group");
-                       goto end;
-               }
 
-               target_action = lttng_action_group_borrow_mutable_at_index(
-                               trigger_action,
-                               LTTNG_OPTIONAL_GET(query_action->action_index));
-       }
-
-end:
-       return target_action;
+       return get_trigger_action_from_path(
+                       trigger, &query_action->action_path);
 }
 
 LTTNG_HIDDEN
@@ -700,7 +755,7 @@ int lttng_error_query_serialize(const struct lttng_error_query *query,
                struct lttng_payload *payload)
 {
        int ret;
-       struct lttng_error_query_comm header = {
+       const struct lttng_error_query_comm header = {
                .target_type = (typeof(header.target_type)) query->target_type,
        };
 
@@ -718,6 +773,13 @@ int lttng_error_query_serialize(const struct lttng_error_query *query,
                        goto end;
                }
 
+               break;
+       case LTTNG_ERROR_QUERY_TARGET_TYPE_CONDITION:
+               ret = lttng_error_query_condition_serialize(query, payload);
+               if (ret) {
+                       goto end;
+               }
+
                break;
        case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION:
                ret = lttng_error_query_action_serialize(query, payload);
@@ -782,28 +844,41 @@ ssize_t lttng_error_query_create_from_payload(struct lttng_payload_view *view,
 
                break;
        }
-       case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION:
+       case LTTNG_ERROR_QUERY_TARGET_TYPE_CONDITION:
        {
-               const struct lttng_action *target_action;
                ssize_t trigger_used_size;
-               struct lttng_error_query_action_comm *action_header;
+               struct lttng_payload_view trigger_view =
+                               lttng_payload_view_from_view(
+                                               view, used_size, -1);
 
-               {
-                       struct lttng_payload_view action_header_view =
-                                       lttng_payload_view_from_view(view,
-                                                       used_size,
-                                                       sizeof(*action_header));
+               if (!lttng_payload_view_is_valid(&trigger_view)) {
+                       used_size = -1;
+                       goto end;
+               }
 
-                       if (!lttng_payload_view_is_valid(&action_header_view)) {
-                               used_size = -1;
-                               goto end;
-                       }
+               trigger_used_size = lttng_trigger_create_from_payload(
+                               &trigger_view, &trigger);
+               if (trigger_used_size < 0) {
+                       used_size = -1;
+                       goto end;
+               }
 
-                       action_header = (typeof(action_header)) action_header_view.buffer.data;
-                       used_size += sizeof(*action_header);
+               used_size += trigger_used_size;
+
+               *query = lttng_error_query_condition_create(trigger);
+               if (!*query) {
+                       used_size = -1;
+                       goto end;
                }
 
+               break;
+       }
+       case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION:
+       {
+               struct lttng_action_path *action_path = NULL;
+
                {
+                       ssize_t trigger_used_size;
                        struct lttng_payload_view trigger_view =
                                        lttng_payload_view_from_view(
                                                        view, used_size, -1);
@@ -823,22 +898,30 @@ ssize_t lttng_error_query_create_from_payload(struct lttng_payload_view *view,
                        used_size += trigger_used_size;
                }
 
-               if (!action_header->action_index.is_set) {
-                       target_action = trigger->action;
-               } else {
-                       if (lttng_action_get_type(trigger->action) !=
-                                       LTTNG_ACTION_TYPE_GROUP) {
+               {
+                       ssize_t action_path_used_size;
+                       struct lttng_payload_view action_path_view =
+                                       lttng_payload_view_from_view(
+                                                       view, used_size, -1);
+
+                       if (!lttng_payload_view_is_valid(&action_path_view)) {
+                               used_size = -1;
+                               goto end;
+                       }
+
+                       action_path_used_size = lttng_action_path_create_from_payload(
+                                       &action_path_view, &action_path);
+                       if (action_path_used_size < 0) {
                                used_size = -1;
                                goto end;
                        }
 
-                       target_action = lttng_action_group_get_at_index(
-                                       trigger->action,
-                                       action_header->action_index.value);
+                       used_size += action_path_used_size;
                }
 
                *query = lttng_error_query_action_create(
-                               trigger, target_action);
+                               trigger, action_path);
+               lttng_action_path_destroy(action_path);
                if (!*query) {
                        used_size = -1;
                        goto end;
@@ -976,3 +1059,176 @@ enum lttng_error_query_result_status lttng_error_query_result_counter_get_value(
 end:
        return status;
 }
+
+static
+enum lttng_error_code lttng_error_query_result_counter_mi_serialize(
+               const struct lttng_error_query_result *result,
+               struct mi_writer *writer)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       enum lttng_error_query_result_status status;
+       uint64_t value;
+
+       assert(result);
+       assert(writer);
+
+       status = lttng_error_query_result_counter_get_value(result, &value);
+       assert(status == LTTNG_ERROR_QUERY_RESULT_STATUS_OK);
+
+       /* Open error query result counter element. */
+       ret = mi_lttng_writer_open_element(
+                       writer, mi_lttng_element_error_query_result_counter);
+       if (ret) {
+               goto mi_error;
+       }
+
+       /* Value. */
+       ret = mi_lttng_writer_write_element_unsigned_int(writer,
+                       mi_lttng_element_error_query_result_counter_value,
+                       value);
+       if (ret) {
+               goto mi_error;
+       }
+
+       /* Close error query result counter element. */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               goto mi_error;
+       }
+
+       ret_code = LTTNG_OK;
+       goto end;
+
+mi_error:
+       ret_code = LTTNG_ERR_MI_IO_FAIL;
+end:
+       return ret_code;
+}
+
+static
+enum lttng_error_code lttng_error_query_result_mi_serialize(
+               const struct lttng_error_query_result *result,
+               struct mi_writer *writer)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       enum lttng_error_query_result_status result_status;
+       enum lttng_error_query_result_type type;
+       const char *name = NULL;
+       const char *description = NULL;
+
+       assert(result);
+       assert(writer);
+
+       type = lttng_error_query_result_get_type(result);
+
+       result_status = lttng_error_query_result_get_name(result, &name);
+       assert(result_status == LTTNG_ERROR_QUERY_RESULT_STATUS_OK);
+
+       result_status = lttng_error_query_result_get_description(
+                       result, &description);
+       assert(result_status == LTTNG_ERROR_QUERY_RESULT_STATUS_OK);
+
+       /* Open error query result element. */
+       ret = mi_lttng_writer_open_element(
+                       writer, mi_lttng_element_error_query_result);
+       if (ret) {
+               goto mi_error;
+       }
+
+       /* Name. */
+       ret = mi_lttng_writer_write_element_string(
+                       writer, mi_lttng_element_error_query_result_name, name);
+       if (ret) {
+               goto mi_error;
+       }
+
+       /* Description. */
+       ret = mi_lttng_writer_write_element_string(writer,
+                       mi_lttng_element_error_query_result_description,
+                       description);
+       if (ret) {
+               goto mi_error;
+       }
+
+       /* Serialize the result according to its sub type. */
+       switch (type) {
+       case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER:
+               ret_code = lttng_error_query_result_counter_mi_serialize(
+                               result, writer);
+               break;
+       default:
+               abort();
+       }
+
+       if (ret_code != LTTNG_OK) {
+               goto end;
+       }
+
+       /* Close error query result element. */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               goto mi_error;
+       }
+
+       ret_code = LTTNG_OK;
+       goto end;
+
+mi_error:
+       ret_code = LTTNG_ERR_MI_IO_FAIL;
+end:
+       return ret_code;
+}
+
+LTTNG_HIDDEN
+enum lttng_error_code lttng_error_query_results_mi_serialize(
+               const struct lttng_error_query_results *results,
+               struct mi_writer *writer)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       unsigned int i, count;
+       enum lttng_error_query_results_status results_status;
+
+       assert(results);
+       assert(writer);
+
+       /* Open error query results element. */
+       ret = mi_lttng_writer_open_element(
+                       writer, mi_lttng_element_error_query_results);
+       if (ret) {
+               goto mi_error;
+       }
+
+       results_status = lttng_error_query_results_get_count(results, &count);
+       assert(results_status == LTTNG_ERROR_QUERY_RESULTS_STATUS_OK);
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_error_query_result *result;
+
+               results_status = lttng_error_query_results_get_result(
+                               results, &result, i);
+               assert(results_status == LTTNG_ERROR_QUERY_RESULTS_STATUS_OK);
+
+               /* A single error query result. */
+               ret_code = lttng_error_query_result_mi_serialize(result, writer);
+               if (ret_code != LTTNG_OK) {
+                       goto end;
+               }
+       }
+
+       /* Close error query results. */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               goto mi_error;
+       }
+
+       ret_code = LTTNG_OK;
+       goto end;
+
+mi_error:
+       ret_code = LTTNG_ERR_MI_IO_FAIL;
+end:
+       return ret_code;
+}
This page took 0.030916 seconds and 4 git commands to generate.