4 * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * SPDX-License-Identifier: GPL-2.1-only
10 #include <common/dynamic-array.h>
11 #include <common/error.h>
12 #include <common/macros.h>
13 #include <common/sessiond-comm/sessiond-comm.h>
14 #include <lttng/action/action-internal.h>
15 #include <lttng/action/list-internal.h>
16 #include <lttng/action/path-internal.h>
17 #include <lttng/error-query-internal.h>
18 #include <lttng/error-query.h>
19 #include <lttng/trigger/trigger-internal.h>
22 struct lttng_error_query
{
23 enum lttng_error_query_target_type target_type
;
26 struct lttng_error_query_comm
{
27 /* enum lttng_error_query_target_type */
29 /* Target-specific payload. */
33 struct lttng_error_query_trigger
{
34 struct lttng_error_query parent
;
35 /* Mutable only because of the reference count. */
36 struct lttng_trigger
*trigger
;
39 struct lttng_error_query_action_comm
{
40 LTTNG_OPTIONAL_COMM(uint32_t) action_index
;
41 /* Trigger payload. */
45 struct lttng_error_query_action
{
46 struct lttng_error_query parent
;
47 /* Mutable only because of the reference count. */
48 struct lttng_trigger
*trigger
;
50 * Index of the target action. Since action lists can't be nested,
51 * the targetted action is the top-level list if the action_index is
52 * unset. Otherwise, the index refers to the index within the top-level
55 LTTNG_OPTIONAL(unsigned int) action_index
;
58 struct lttng_error_query_result
{
59 enum lttng_error_query_result_type type
;
64 struct lttng_error_query_result_comm
{
65 /* enum lttng_error_query_result_type */
67 /* Length of name (including null-terminator). */
69 /* Length of description (including null-terminator). */
70 uint32_t description_len
;
71 /* Name, description, and type-specific payload follow. */
75 struct lttng_error_query_result_counter_comm
{
79 struct lttng_error_query_result_counter
{
80 struct lttng_error_query_result parent
;
84 struct lttng_error_query_results_comm
{
86 /* `count` instances of `struct lttng_error_query_result` follow. */
90 struct lttng_error_query_results
{
91 struct lttng_dynamic_pointer_array results
;
95 struct lttng_error_query
*lttng_error_query_trigger_create(
96 const struct lttng_trigger
*trigger
)
98 struct lttng_error_query_trigger
*query
= NULL
;
99 struct lttng_trigger
*trigger_copy
= NULL
;
105 trigger_copy
= lttng_trigger_copy(trigger
);
110 query
= zmalloc(sizeof(*query
));
112 PERROR("Failed to allocate trigger error query");
116 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
;
117 query
->trigger
= trigger_copy
;
121 lttng_trigger_put(trigger_copy
);
123 return query
? &query
->parent
: NULL
;
126 extern struct lttng_error_query
*lttng_error_query_action_create(
127 const struct lttng_trigger
*trigger
,
128 const struct lttng_action
*action
)
130 struct lttng_error_query_action
*query
= NULL
;
131 typeof(query
->action_index
) action_index
= {};
132 struct lttng_trigger
*trigger_copy
= NULL
;
134 if (!trigger
|| !action
) {
138 trigger_copy
= lttng_trigger_copy(trigger
);
144 * If an action is not the top-level action of the trigger, our only
145 * hope of finding its position is if the top-level action is an
148 * Note that action comparisons are performed by pointer since multiple
149 * otherwise identical actions can be found in an action list (two
150 * notify actions, for example).
152 if (action
!= trigger
->action
&&
153 lttng_action_get_type(trigger
->action
) ==
154 LTTNG_ACTION_TYPE_LIST
) {
155 unsigned int i
, action_list_count
;
156 enum lttng_action_status action_status
;
158 action_status
= lttng_action_list_get_count(
159 trigger
->action
, &action_list_count
);
160 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
164 for (i
= 0; i
< action_list_count
; i
++) {
165 const struct lttng_action
*candidate_action
=
166 lttng_action_list_get_at_index(
169 assert(candidate_action
);
170 if (candidate_action
== action
) {
171 LTTNG_OPTIONAL_SET(&action_index
, i
);
176 if (!action_index
.is_set
) {
177 /* Not found; invalid action. */
182 * Trigger action is not a list and not equal to the target
183 * action; invalid action provided.
188 query
= zmalloc(sizeof(*query
));
190 PERROR("Failed to allocate action error query");
194 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
;
195 query
->trigger
= trigger_copy
;
197 query
->action_index
= action_index
;
199 lttng_trigger_put(trigger_copy
);
201 return query
? &query
->parent
: NULL
;
204 void lttng_error_query_destroy(struct lttng_error_query
*query
)
206 struct lttng_error_query_trigger
*trigger_query
;
212 trigger_query
= container_of(query
, typeof(*trigger_query
), parent
);
213 lttng_trigger_put(trigger_query
->trigger
);
218 int lttng_error_query_result_counter_serialize(
219 const struct lttng_error_query_result
*result
,
220 struct lttng_payload
*payload
)
222 const struct lttng_error_query_result_counter
*counter_result
;
224 assert(result
->type
== LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
);
225 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
227 return lttng_dynamic_buffer_append(&payload
->buffer
,
228 &(struct lttng_error_query_result_counter_comm
) {
229 .value
= counter_result
->value
231 sizeof(struct lttng_error_query_result_counter_comm
));
235 int lttng_error_query_result_serialize(
236 const struct lttng_error_query_result
*result
,
237 struct lttng_payload
*payload
)
240 struct lttng_error_query_result_comm header
= {
241 .type
= (uint8_t) result
->type
,
242 .name_len
= (typeof(header
.name_len
)) strlen(result
->name
) + 1,
243 .description_len
= (typeof(header
.name_len
)) strlen(result
->description
) + 1,
247 ret
= lttng_dynamic_buffer_append(
248 &payload
->buffer
, &header
, sizeof(header
));
250 ERR("Failed to append error query result communication header to payload");
255 ret
= lttng_dynamic_buffer_append(
256 &payload
->buffer
, result
->name
, header
.name_len
);
258 ERR("Failed to append error query result name to payload");
263 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, result
->description
,
264 header
.description_len
);
266 ERR("Failed to append error query result description to payload");
270 /* Type-specific payload. */
271 switch (result
->type
) {
272 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
273 ret
= lttng_error_query_result_counter_serialize(
276 ERR("Failed to serialize counter error query result");
289 int lttng_error_query_result_init(
290 struct lttng_error_query_result
*result
,
291 enum lttng_error_query_result_type result_type
,
293 const char *description
)
300 result
->type
= result_type
;
302 result
->name
= strdup(name
);
304 PERROR("Failed to copy error query result name");
309 result
->description
= strdup(description
);
310 if (!result
->description
) {
311 PERROR("Failed to copy error query result description");
322 void lttng_error_query_result_destroy(struct lttng_error_query_result
*counter
)
328 switch (counter
->type
) {
329 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
330 /* Nothing to tear down. */
337 free(counter
->description
);
342 struct lttng_error_query_result
*
343 lttng_error_query_result_counter_create(
344 const char *name
, const char *description
, uint64_t value
)
347 struct lttng_error_query_result_counter
*counter
;
349 counter
= zmalloc(sizeof(*counter
));
351 PERROR("Failed to allocate error query counter result");
355 init_ret
= lttng_error_query_result_init(&counter
->parent
,
356 LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
, name
,
362 counter
->value
= value
;
365 lttng_error_query_result_destroy(&counter
->parent
);
367 return counter
? &counter
->parent
: NULL
;
371 void destroy_result(void *ptr
)
373 struct lttng_error_query_result
*result
= (typeof(result
)) ptr
;
375 lttng_error_query_result_destroy(result
);
379 struct lttng_error_query_results
*lttng_error_query_results_create(void)
381 struct lttng_error_query_results
*set
= zmalloc(sizeof(*set
));
384 PERROR("Failed to allocate an error query result set");
388 lttng_dynamic_pointer_array_init(&set
->results
, destroy_result
);
394 int lttng_error_query_results_add_result(
395 struct lttng_error_query_results
*results
,
396 struct lttng_error_query_result
*result
)
398 return lttng_dynamic_pointer_array_add_pointer(
399 &results
->results
, result
);
403 ssize_t
lttng_error_query_result_create_from_payload(
404 struct lttng_payload_view
*view
,
405 struct lttng_error_query_result
**result
)
407 ssize_t used_size
= 0;
408 struct lttng_error_query_result_comm
*header
;
409 struct lttng_payload_view header_view
=
410 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
412 const char *description
;
414 if (!lttng_payload_view_is_valid(&header_view
)) {
419 header
= (typeof(header
)) header_view
.buffer
.data
;
420 used_size
+= sizeof(*header
);
423 struct lttng_payload_view name_view
=
424 lttng_payload_view_from_view(view
, used_size
,
427 if (!lttng_payload_view_is_valid(&name_view
) ||
428 !lttng_buffer_view_contains_string(
430 name_view
.buffer
.data
,
436 name
= name_view
.buffer
.data
;
437 used_size
+= header
->name_len
;
441 struct lttng_payload_view description_view
=
442 lttng_payload_view_from_view(view
, used_size
,
443 header
->description_len
);
445 if (!lttng_payload_view_is_valid(&description_view
) ||
446 !lttng_buffer_view_contains_string(
447 &description_view
.buffer
,
448 description_view
.buffer
.data
,
449 header
->description_len
)) {
454 description
= description_view
.buffer
.data
;
455 used_size
+= header
->description_len
;
458 switch (header
->type
) {
459 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
461 struct lttng_error_query_result_counter_comm
*counter
;
462 struct lttng_payload_view counter_payload_view
=
463 lttng_payload_view_from_view(view
, used_size
,
466 if (!lttng_payload_view_is_valid(&counter_payload_view
)) {
471 counter
= (typeof(counter
)) counter_payload_view
.buffer
.data
;
472 *result
= lttng_error_query_result_counter_create(
473 name
, description
, counter
->value
);
479 used_size
+= sizeof(*counter
);
492 int lttng_error_query_results_serialize(
493 const struct lttng_error_query_results
*results
,
494 struct lttng_payload
*payload
)
498 const size_t result_count
= lttng_dynamic_pointer_array_get_count(
500 const struct lttng_error_query_results_comm header
= {
501 .count
= (typeof(header
.count
)) result_count
,
505 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &header
, sizeof(header
));
507 ERR("Failed to append error query result set header to payload");
512 for (result_index
= 0; result_index
< result_count
; result_index
++) {
513 const struct lttng_error_query_result
*result
= (typeof(result
))
514 lttng_dynamic_pointer_array_get_pointer(
518 ret
= lttng_error_query_result_serialize(result
, payload
);
520 ERR("Failed to append error query result to payload");
529 ssize_t
lttng_error_query_results_create_from_payload(
530 struct lttng_payload_view
*view
,
531 struct lttng_error_query_results
**_results
)
534 ssize_t total_used_size
= 0;
535 struct lttng_error_query_results_comm
*header
;
536 struct lttng_payload_view header_view
=
537 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
538 struct lttng_error_query_results
*results
= NULL
;
540 if (!lttng_payload_view_is_valid(&header_view
)) {
541 ERR("Failed to map view to error query result set header");
542 total_used_size
= -1;
546 header
= (typeof(header
)) header_view
.buffer
.data
;
547 total_used_size
+= sizeof(*header
);
548 results
= lttng_error_query_results_create();
550 total_used_size
= -1;
554 for (result_index
= 0; result_index
< header
->count
; result_index
++) {
556 struct lttng_error_query_result
*result
;
557 struct lttng_payload_view result_view
=
558 lttng_payload_view_from_view(
559 view
, total_used_size
, -1);
561 if (!lttng_payload_view_is_valid(&result_view
)) {
562 total_used_size
= -1;
566 used_size
= lttng_error_query_result_create_from_payload(
567 &result_view
, &result
);
569 total_used_size
= -1;
573 total_used_size
+= used_size
;
575 if (lttng_dynamic_pointer_array_add_pointer(
576 &results
->results
, result
)) {
577 lttng_error_query_result_destroy(result
);
578 total_used_size
= -1;
586 lttng_error_query_results_destroy(results
);
587 return total_used_size
;
591 int lttng_error_query_trigger_serialize(const struct lttng_error_query
*query
,
592 struct lttng_payload
*payload
)
595 const struct lttng_error_query_trigger
*query_trigger
=
596 container_of(query
, typeof(*query_trigger
), parent
);
598 if (!lttng_trigger_validate(query_trigger
->trigger
)) {
603 ret
= lttng_trigger_serialize(query_trigger
->trigger
, payload
);
613 int lttng_error_query_action_serialize(const struct lttng_error_query
*query
,
614 struct lttng_payload
*payload
)
617 const struct lttng_error_query_action
*query_action
=
618 container_of(query
, typeof(*query_action
), parent
);
619 struct lttng_error_query_action_comm header
= {
620 .action_index
.is_set
= query_action
->action_index
.is_set
,
621 .action_index
.value
= query_action
->action_index
.value
,
624 if (!lttng_trigger_validate(query_action
->trigger
)) {
629 ret
= lttng_dynamic_buffer_append(
630 &payload
->buffer
, &header
, sizeof(header
));
635 ret
= lttng_trigger_serialize(query_action
->trigger
, payload
);
644 enum lttng_error_query_target_type
lttng_error_query_get_target_type(
645 const struct lttng_error_query
*query
)
647 return query
->target_type
;
651 const struct lttng_trigger
*lttng_error_query_trigger_borrow_target(
652 const struct lttng_error_query
*query
)
654 const struct lttng_error_query_trigger
*query_trigger
=
655 container_of(query
, typeof(*query_trigger
), parent
);
657 return query_trigger
->trigger
;
661 const struct lttng_trigger
*lttng_error_query_action_borrow_trigger_target(
662 const struct lttng_error_query
*query
)
664 const struct lttng_error_query_action
*query_action
=
665 container_of(query
, typeof(*query_action
), parent
);
667 return query_action
->trigger
;
671 struct lttng_action
*lttng_error_query_action_borrow_action_target(
672 const struct lttng_error_query
*query
,
673 struct lttng_trigger
*trigger
)
675 struct lttng_action
*target_action
= NULL
;
676 const struct lttng_error_query_action
*query_action
=
677 container_of(query
, typeof(*query_action
), parent
);
678 struct lttng_action
*trigger_action
=
679 lttng_trigger_get_action(trigger
);
681 if (!query_action
->action_index
.is_set
) {
682 target_action
= trigger_action
;
684 if (lttng_action_get_type(trigger_action
) !=
685 LTTNG_ACTION_TYPE_LIST
) {
686 ERR("Invalid action error query target index: trigger action is not a list");
690 target_action
= lttng_action_list_borrow_mutable_at_index(
692 LTTNG_OPTIONAL_GET(query_action
->action_index
));
696 return target_action
;
700 int lttng_error_query_serialize(const struct lttng_error_query
*query
,
701 struct lttng_payload
*payload
)
704 struct lttng_error_query_comm header
= {
705 .target_type
= (typeof(header
.target_type
)) query
->target_type
,
708 ret
= lttng_dynamic_buffer_append(
709 &payload
->buffer
, &header
, sizeof(header
));
711 ERR("Failed to append error query header to payload");
715 switch (query
->target_type
) {
716 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
717 ret
= lttng_error_query_trigger_serialize(query
, payload
);
723 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
724 ret
= lttng_error_query_action_serialize(query
, payload
);
738 ssize_t
lttng_error_query_create_from_payload(struct lttng_payload_view
*view
,
739 struct lttng_error_query
**query
)
741 ssize_t used_size
= 0;
742 struct lttng_error_query_comm
*header
;
743 struct lttng_trigger
*trigger
= NULL
;
744 struct lttng_payload_view header_view
=
745 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
747 if (!lttng_payload_view_is_valid(&header_view
)) {
748 ERR("Failed to map error query header");
753 used_size
= sizeof(*header
);
755 header
= (typeof(header
)) header_view
.buffer
.data
;
756 switch ((enum lttng_error_query_target_type
) header
->target_type
) {
757 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
759 ssize_t trigger_used_size
;
760 struct lttng_payload_view trigger_view
=
761 lttng_payload_view_from_view(
762 view
, used_size
, -1);
764 if (!lttng_payload_view_is_valid(&trigger_view
)) {
769 trigger_used_size
= lttng_trigger_create_from_payload(
770 &trigger_view
, &trigger
);
771 if (trigger_used_size
< 0) {
776 used_size
+= trigger_used_size
;
778 *query
= lttng_error_query_trigger_create(trigger
);
786 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
788 const struct lttng_action
*target_action
;
789 ssize_t trigger_used_size
;
790 struct lttng_error_query_action_comm
*action_header
;
793 struct lttng_payload_view action_header_view
=
794 lttng_payload_view_from_view(view
,
796 sizeof(*action_header
));
798 if (!lttng_payload_view_is_valid(&action_header_view
)) {
803 action_header
= (typeof(action_header
)) action_header_view
.buffer
.data
;
804 used_size
+= sizeof(*action_header
);
808 struct lttng_payload_view trigger_view
=
809 lttng_payload_view_from_view(
810 view
, used_size
, -1);
812 if (!lttng_payload_view_is_valid(&trigger_view
)) {
817 trigger_used_size
= lttng_trigger_create_from_payload(
818 &trigger_view
, &trigger
);
819 if (trigger_used_size
< 0) {
824 used_size
+= trigger_used_size
;
827 if (!action_header
->action_index
.is_set
) {
828 target_action
= trigger
->action
;
830 if (lttng_action_get_type(trigger
->action
) !=
831 LTTNG_ACTION_TYPE_LIST
) {
836 target_action
= lttng_action_list_get_at_index(
838 action_header
->action_index
.value
);
841 *query
= lttng_error_query_action_create(
842 trigger
, target_action
);
856 lttng_trigger_put(trigger
);
860 enum lttng_error_query_results_status
lttng_error_query_results_get_count(
861 const struct lttng_error_query_results
*results
,
864 enum lttng_error_query_results_status status
;
866 if (!results
|| !count
) {
867 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
871 *count
= lttng_dynamic_pointer_array_get_count(&results
->results
);
872 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
877 enum lttng_error_query_results_status
878 lttng_error_query_results_get_result(
879 const struct lttng_error_query_results
*results
,
880 const struct lttng_error_query_result
**result
,
883 unsigned int result_count
;
884 enum lttng_error_query_results_status status
;
886 if (!results
|| !result
) {
887 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
891 status
= lttng_error_query_results_get_count(results
, &result_count
);
892 if (status
!= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
) {
896 if (index
>= result_count
) {
897 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
901 *result
= (typeof(*result
)) lttng_dynamic_pointer_array_get_pointer(
902 &results
->results
, index
);
904 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
909 void lttng_error_query_results_destroy(
910 struct lttng_error_query_results
*results
)
916 lttng_dynamic_pointer_array_reset(&results
->results
);
920 enum lttng_error_query_result_type
921 lttng_error_query_result_get_type(const struct lttng_error_query_result
*result
)
923 return result
? result
->type
: LTTNG_ERROR_QUERY_RESULT_TYPE_UNKNOWN
;
926 enum lttng_error_query_result_status
lttng_error_query_result_get_name(
927 const struct lttng_error_query_result
*result
,
930 enum lttng_error_query_result_status status
;
932 if (!result
|| !name
) {
933 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
937 *name
= result
->name
;
938 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
943 enum lttng_error_query_result_status
lttng_error_query_result_get_description(
944 const struct lttng_error_query_result
*result
,
945 const char **description
)
947 enum lttng_error_query_result_status status
;
949 if (!result
|| !description
) {
950 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
954 *description
= result
->description
;
955 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
960 enum lttng_error_query_result_status
lttng_error_query_result_counter_get_value(
961 const struct lttng_error_query_result
*result
,
964 enum lttng_error_query_result_status status
;
965 const struct lttng_error_query_result_counter
*counter_result
;
967 if (!result
|| !value
||
968 result
->type
!= LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
) {
969 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
973 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
975 *value
= counter_result
->value
;
976 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;